게터와 세터?
저는 PHP 개발자가 아니기 때문에 PHP에서 명시적인 getter/setter를 순수한 OOP 스타일로 사용할 경우의 장점과 단점은 무엇인지 궁금합니다(제가 좋아하는 방식).
class MyClass {
private $firstField;
private $secondField;
public function getFirstField() {
return $this->firstField;
}
public function setFirstField($x) {
$this->firstField = $x;
}
public function getSecondField() {
return $this->secondField;
}
public function setSecondField($x) {
$this->secondField = $x;
}
}
또는 퍼블릭 필드만:
class MyClass {
public $firstField;
public $secondField;
}
php magic 메서드를 사용할 수 있습니다. __get
★★★★★★★★★★★★★★★★★」__set
.
<?php
class MyClass {
private $firstField;
private $secondField;
public function __get($property) {
if (property_exists($this, $property)) {
return $this->$property;
}
}
public function __set($property, $value) {
if (property_exists($this, $property)) {
$this->$property = $value;
}
return $this;
}
}
?>
왜 getter와 setter를 사용하는가?
- 확장성:프로젝트 코드의 모든 var 할당을 검색하는 것보다 getter를 재팩터화하는 것이 더 쉽습니다.
- 디버깅:세터나 게터에 브레이크 포인트를 둘 수 있습니다.
- 클리너: 매직 기능은 쓰기 횟수를 줄이는 데 적합하지 않습니다.IDE 에서는 코드를 제안하지 않습니다.빠른 쓰기 getter에는 템플릿을 사용하는 것이 좋습니다.
Google은 이미 PHP 최적화에 대한 가이드를 발행했고 결론은 다음과 같습니다.
getter 및 setter 없음 PHP 최적화
그리고 당신은 마법의 방법을 사용해서는 안됩니다.PHP에게 매직 메서드는 사악합니다. 왜일까요?
- 디버깅은 어렵습니다.
- 퍼포먼스에 부정적인 영향이 있습니다.
- 더 많은 코드를 작성해야 합니다.
PHP는 Java, C++ 또는 C#이 아닙니다.PHP는 다르며 다른 규칙을 사용합니다.
캡슐화는 어떤 OO 언어든 중요하며, 인기는 아무런 관련이 없습니다.PHP와 같은 동적 유형 언어에서는 특히 세터를 사용하지 않고 속성을 특정 유형으로 만들 수 있는 방법이 거의 없기 때문에 유용합니다.
PHP에서는 다음과 같이 동작합니다.
class Foo {
public $bar; // should be an integer
}
$foo = new Foo;
$foo->bar = "string";
Java에서는 다음 기능이 없습니다.
class Foo {
public int bar;
}
Foo myFoo = new Foo();
myFoo.bar = "string"; // error
의 방법의 사용)__get
★★★★★★★★★★★★★★★★★」__set
만, 하고 있는 도 동작합니다만, 현재 스코프가 액세스 할 수 있는 것보다 가시성이 낮은 속성에 액세스 하고 있는 경우 뿐입니다.올바르게 사용하지 않으면 디버깅을 시도할 때 두통이 생기기 쉽습니다.
__call 함수를 사용하는 경우 이 메서드를 사용할 수 있습니다.와 함께 동작합니다.
- = > GET = >
$this->property()
- = > SET = >
$this->property($value)
- = > GET = >
$this->getProperty()
- = > SET = >
$this->setProperty($value)
칼즈
public function __call($name, $arguments) {
//Getting and setting with $this->property($optional);
if (property_exists(get_class($this), $name)) {
//Always set the value if a parameter is passed
if (count($arguments) == 1) {
/* set */
$this->$name = $arguments[0];
} else if (count($arguments) > 1) {
throw new \Exception("Setter for $name only accepts one parameter.");
}
//Always return the value (Even on the set)
return $this->$name;
}
//If it doesn't chech if its a normal old type setter ot getter
//Getting and setting with $this->getProperty($optional);
//Getting and setting with $this->setProperty($optional);
$prefix = substr($name, 0, 3);
$property = strtolower($name[3]) . substr($name, 4);
switch ($prefix) {
case 'get':
return $this->$property;
break;
case 'set':
//Always set the value if a parameter is passed
if (count($arguments) != 1) {
throw new \Exception("Setter for $name requires exactly one parameter.");
}
$this->$property = $arguments[0];
//Always return the value (Even on the set)
return $this->$name;
default:
throw new \Exception("Property $name doesn't exist.");
break;
}
}
여기에 이미 훌륭하고 존경받는 답변에 더해 세터/게터가 없는 PHP로 확장하고 싶습니다.
PHP에는 getter 및 setter 구문이 없습니다.Dave가 지적한 대로 속성 조회 프로세스를 "후크"하고 재정의할 수 있는 하위 클래스 또는 마법 방법을 제공합니다.
매직은 게으른 프로그래머가 프로젝트에 적극적으로 관여하고 있는 시점에서 보다 적은 코드로 보다 많은 작업을 수행할 수 있도록 합니다.다만, 통상은 가독성을 희생합니다.
퍼포먼스 PHP에서 getter/setter와 같은 코드 아키텍처를 강제적으로 실행함으로써 발생하는 불필요한 모든 함수는 호출 시 자체 메모리 스택 프레임을 포함하고 CPU 사이클을 낭비하고 있습니다.
가독성:코드 베이스는 코드 라인을 부풀리게 합니다.이것은 LOC가 많을수록 스크롤이 많아지기 때문에 코드 네비게이션에 영향을 줍니다.
기본 설정:개인적인 경험으로 봤을 때, 나는 정적 코드 분석의 실패를 마법의 길을 가는 것을 피하기 위한 신호로 받아들인다. 그 때 분명히 장기적인 이익이 나에게 주어지지 않는 한.
오류:
이치노를 들면, 「」라고 하는 것은…….$someobject->width
가 $someobject->width()
하지만 행성과는 달리circumference
★★★★★★★★★★★★★★★★★」width
할 수 static
의)$someobject
폭 함수를 필요로 하는 경우 오브젝트의 인스턴스 폭을 측정할 수 있습니다.
따라서 가독성은 주로 특정 속성 값을 출력하는 함수를 숨김으로써가 아니라 적극적인 명명 스킴에 의해 높아집니다.
__get / __set 용도:
부동산 가치의 사전 검증 및 사전 관리
스트링.
" some {mathsobj1->generatelatex} multi line text {mathsobj1->latexoutput} with lots of variables for {mathsobj1->generatelatex} some reason "
경우, 「 」
generatelatex
+메서드명+메서드명의 합니다.특별하고 명백한 경우
$dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated() $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()
주의: PHP는 getter/setter 구문을 구현하지 않기로 선택했습니다.getter/setter가 일반적으로 나쁘다고 주장하는 것은 아닙니다.
class MyClass {
private $firstField;
private $secondField;
private $thirdField;
public function __get( $name ) {
if( method_exists( $this , $method = ( 'get' . ucfirst( $name ) ) ) )
return $this->$method();
else
throw new Exception( 'Can\'t get property ' . $name );
}
public function __set( $name , $value ) {
if( method_exists( $this , $method = ( 'set' . ucfirst( $name ) ) ) )
return $this->$method( $value );
else
throw new Exception( 'Can\'t set property ' . $name );
}
public function __isset( $name )
{
return method_exists( $this , 'get' . ucfirst( $name ) )
|| method_exists( $this , 'set' . ucfirst( $name ) );
}
public function getFirstField() {
return $this->firstField;
}
protected function setFirstField($x) {
$this->firstField = $x;
}
private function getSecondField() {
return $this->secondField;
}
}
$obj = new MyClass();
echo $obj->firstField; // works
$obj->firstField = 'value'; // works
echo $obj->getFirstField(); // works
$obj->setFirstField( 'value' ); // not works, method is protected
echo $obj->secondField; // works
echo $obj->getSecondField(); // not works, method is private
$obj->secondField = 'value'; // not works, setter not exists
echo $obj->thirdField; // not works, property not exists
isset( $obj->firstField ); // returns true
isset( $obj->secondField ); // returns true
isset( $obj->thirdField ); // returns false
준비!
마법의 방법 __call을 사용하여 실험을 했습니다.다른 답변 및 댓글에 "매직 메서드 사용 안 함" 경고가 모두 표시되므로 게시해야 할지 모르겠습니다만, 여기에 남겨둡니다.혹시나 유용하다고 생각할지 모르니까
public function __call($_name, $_arguments){
$action = substr($_name, 0, 4);
$varName = substr($_name, 4);
if (isset($this->{$varName})){
if ($action === "get_") return $this->{$varName};
if ($action === "set_") $this->{$varName} = $_arguments[0];
}
}
위의 메서드를 클래스에 추가하면 다음과 같이 입력할 수 있습니다.
class MyClass{
private foo = "bar";
private bom = "bim";
// ...
// public function __call(){ ... }
// ...
}
$C = new MyClass();
// as getter
$C->get_foo(); // return "bar"
$C->get_bom(); // return "bim"
// as setter
$C->set_foo("abc"); // set "abc" as new value of foo
$C->set_bom("zam"); // set "zam" as new value of bom
이렇게 하면 클래스의 모든 항목이 존재하는 경우 가져오거나 설정할 수 있습니다. 따라서 일부 특정 요소에만 필요한 경우 "화이트리스트"를 필터로 사용할 수 있습니다.
예:
private $callWhiteList = array(
"foo" => "foo",
"fee" => "fee",
// ...
);
public function __call($_name, $_arguments){
$action = substr($_name, 0, 4);
$varName = $this->callWhiteList[substr($_name, 4)];
if (!is_null($varName) && isset($this->{$varName})){
if ($action === "get_") return $this->{$varName};
if ($action === "set_") $this->{$varName} = $_arguments[0];
}
}
후우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우우.
또한 이 "화이트리스트"를 사용하여 사용자 지정 이름을 할당하여 대표팀에 액세스할 수 있습니다.
를 들어 '예'라고 하면,
private $callWhiteList = array(
"myfoo" => "foo",
"zim" => "bom",
// ...
);
이 목록을 사용하여 다음을 입력할 수 있습니다.
class MyClass{
private foo = "bar";
private bom = "bim";
// ...
// private $callWhiteList = array( ... )
// public function __call(){ ... }
// ...
}
$C = new MyClass();
// as getter
$C->get_myfoo(); // return "bar"
$C->get_zim(); // return "bim"
// as setter
$C->set_myfoo("abc"); // set "abc" as new value of foo
$C->set_zim("zam"); // set "zam" as new value of bom
.
.
.
그게 다예요.
Doc: __call()은 오브젝트 컨텍스트에서 액세스 불가능한 메서드를 호출할 때 트리거됩니다.
음, PHP는 마법의 방법을 가지고 있습니다.__get
,__set
,__isset
&__unset
이것은 항상 시작입니다.아아, 제대로 된(알았지?OO의 속성은 마법의 방법 그 이상입니다.PHP 구현의 주요 문제는 액세스할 수 없는 모든 속성에 대해 마법 메서드가 호출된다는 것입니다.즉, 이름이 실제로 객체의 속성인지 여부를 판단할 때 마법 메서드에서 자신을 반복해야 합니다(예를 들어 property_exists()).또한 모든 클래스가 ie에서 상속되지 않는 한 기본 클래스로는 이 일반적인 문제를 해결할 수 없습니다.ClassWithProperties. PHP에는 여러 상속이 없기 때문입니다.
반면 Python의 새로운 스타일 클래스는property()
모든 속성을 명시적으로 정의할 수 있습니다.C#에는 특별한 구문이 있습니다.
http://en.wikipedia.org/wiki/Property_(programming)
다른 조언들을 읽어본 후, 나는 다음과 같이 말하고 싶다.
GENERIC 규칙으로서 모든 속성, 특히 "내부" 속성(세마포어, 내부 플래그...)에 대해 항상 세터를 정의하는 것은 아닙니다.읽기 전용 속성에는 세터가 없습니다.따라서 일부 속성에는 getter만 있습니다.여기서 __get()이 코드를 축소합니다.
- 동일한 모든 속성에 대해 __get()(글로벌 getters 포함)을 정의합니다.
- 어레이로 그룹화하여 다음과 같이 합니다.
- 통화 가치의 형식이 적절하거나 특정 레이아웃의 날짜(ISO, US, 국제) 등 공통적인 특징이 있습니다.
- 코드 자체는 이 마법의 방법을 사용하여 기존 및 허용된 속성만 읽고 있는지 확인할 수 있습니다.
- 유사한 속성을 새로 만들어야 할 때마다 선언하고 이름을 적절한 배열에 추가하면 됩니다.이는 새로운 게터를 정의하는 것보다 훨씬 더 빠릅니다. 아마도 클래스 코드 전체에 몇 줄의 코드가 반복될 것입니다.
네! 이를 위해 개인 메서드를 작성할 수도 있지만, 그 결과 항상 같은 다른 메서드를 호출하게 되는 많은 메서드가 선언됩니다(+메모리).왜 모두를 지배할 수 있는 하나의 방법을 쓰지 않는 거죠?[말장난은 절대 의도! :]
또한 매직 세터는 특정 속성에만 응답할 수 있으므로 모든 날짜 유형 속성을 하나의 메서드로만 비활성 값에 대해 스크리닝할 수 있습니다.날짜 유형 속성이 배열에 나열된 경우 해당 설정자를 쉽게 정의할 수 있습니다.물론, 그냥 예시일 뿐이죠.상황이 너무 많아요
가독성에 대해서...뭐...그건 또 다른 논쟁입니다.IDE의 사용에 얽매이는 것은 싫습니다(사실 IDE를 사용하지 않습니다.IDE는 쓰는 방법을 가르쳐 줍니다).'아름다움'을 코딩하는 걸 좋아하거든요.난 이름 짓는데 집착하는 편이라서 CTags나 다른 보조기구를 몇 개 쓰면 충분해어쨌든, 이 모든 매직세터나 getter가 완성되면, 저는 __set() 메서드로 일반화하기에는 너무 구체적이거나 "특수"인 다른 세터를 씁니다.이것으로 속성을 취득하고 설정하는 데 필요한 모든 것을 알 수 있습니다.물론, 항상 공통의 근거가 있는 것은 아닙니다.또한 마법의 방법을 코딩할 필요가 없는 특성도 몇 가지 있습니다.그리고 오래된 좋은 전통적인 세터/게터 쌍도 있습니다.
프로그래밍 언어는 바로 인간 인공어입니다.각각의 억양이나 억양, 구문, 플레이버가 있기 때문에 Java나 C#과 같은 "accent"를 사용하여 Ruby나 Python 코드를 작성하는 척하지 않을 것입니다.또한 JavaScript나 PHP를 Perl이나 SQL과 비슷하게 만들지도 않을 것입니다.사용하는 방법에 따라 사용합니다.
일반적으로 첫 번째 방법은 PHP로 쉽게 전환하여 객체 지향적인 방식으로 작업을 수행할 수 있기 때문에 전반적으로 더 인기가 있습니다.첫 번째 방법은 좀 더 보편적이다.제 조언은 여러 언어로 시도되고 진실된 것을 고수하라는 것입니다.그러면, 당신이 다른 언어를 사용할 때, 그리고 만약 당신이 무언가를 성취할 준비가 되어 있을 것이다(수레바퀴를 재창조하는 데 시간을 보내는 대신).
Netbeans-Convention에서 소스 코드를 작성하는 방법은 여러 가지가 있습니다.이거 멋진데.=== FALSE를 생각하기 쉬워진다.어떤 속성을 캡슐화해야 하는지, 어떤 속성을 캡슐화하지 말아야 하는지 잘 모를 경우 tradistel을 사용하십시오.알아요, 보이... 플라...debugging-works 및 기타 많은 사람들은 이것이 더 좋고 명확한 방법이라고 생각합니다.간단한 게터나 세터를 만드는 방법을 예술의 끝과 함께 많은 시간을 보내지 마세요.magic을 사용하는 경우 demeter-rule 등의 일부 설계 패턴을 구현할 수 없습니다.특정 상황에서 magic_calls를 사용하거나 작고 빠르고 명확한 솔루션에 사용할 수 있습니다.물론 이런 식으로 디자인 패턴의 솔루션을 만들 수도 있겠지만, 왜 더 힘들게 살아야 하는지.
값 검증 + 형식 지정/파생
setters를 사용하면 데이터를 검증할 수 있으며 getter를 사용하면 데이터를 포맷하거나 파생할 수 있습니다.오브젝트를 사용하면 데이터와 그 검증 및 포맷 코드를 DRY를 권장하는 깔끔한 패키지로 캡슐화할 수 있습니다.
예를 들어, 생년월일이 포함된 다음과 같은 단순 클래스를 고려합니다.
class BirthDate {
private $birth_date;
public function getBirthDate($format='Y-m-d') {
//format $birth_date ...
//$birth_date = ...
return $birth_date;
}
public function setBirthDate($birth_date) {
//if($birth_date is not valid) throw an exception ...
$this->birth_date = $birth_date;
}
public function getAge() {
//calculate age ...
return $age;
}
public function getDaysUntilBirthday() {
//calculate days until birth days
return $days;
}
}
설정되는 값이 다음 값인지 검증할 수 있습니다.
- 유효일
- 미래에는 안 된다
또, 이 검증을 애플리케이션 전체(또는 복수의 애플리케이션 전체)에 걸쳐 실시하는 것은 바람직하지 않습니다.대신 멤버 변수를 보호 또는 비공개로 하고(세터를 유일한 액세스포인트로 만들기 위해), 세터로 검증하는 것이 쉬워집니다.그러면 오브젝트가 어플리케이션의 어느 부분에서 왔는지와 관계없이 오브젝트에 유효한 생년월일이 포함되어 있음을 알 수 있기 때문입니다.또한 검증을 추가할 경우 오브젝트를 sin에 추가할 수 있습니다.장소를 고르다.
같은 멤버 변수에서 동작하는 여러 포맷터를 추가할 수 있습니다. getAge()
★★★★★★★★★★★★★★★★★」getDaysUntilBirthday()
설정 .getBirthDate()
로케일에 따라 다릅니다. 저는 therefore therefore therefore therefore therefore therefore therefore therefore therefore therefore를 섞는 것보다 를 통해 일관되게 값에 접근하는 것을 합니다.$date->getAge()
$date->birth_date
.
objects.getters의 setters를 합니다.예를 들어, 프로그램이 일부 지역에서는 150년 이상의 생년월일을 허용해야 한다고 가정합니다.하지 않고 할 수 있는 중 하나는 '코드가 없다'를 확장하는 입니다.BirthDate
오브젝트를 설정하고 추가 검증을 세터에 넣습니다.
class LivingBirthDate extends BirthDate {
public function setBirthDate($birth_date) {
//if $birth_date is greater than 150 years throw an exception
//else pass to parent's setter
return parent::setBirthDate($birth_date);
}
}
이 투고는 특별히 에 관한 것이 아닙니다.__get
★★★★★★★★★★★★★★★★★」__set
__call
메서드 호출 이외에는 같은 생각입니다.원칙적으로 코멘트나 투고에 기재되어 있는 이유로 오버로드가 가능한 모든 종류의 마법 메서드는 피하고 있습니다만, 최근 SERVICE와 SUB-SERVICE를 사용하는 서드파티 API를 발견했습니다.예를 들어 다음과 같습니다.
http://3rdparty.api.com?service=APIService.doActionOne&apikey=12341234
은 이 하고 모든 이 API는 서브액션을 제외하고 모두 동일합니다.doActionOne
개발자(나 자신 및 이 클래스를 사용하는 다른 사람)는 다음과 같은 것과는 달리 서브 서비스를 이름으로 호출할 수 있습니다.
$myClass->doAction(array('service'=>'doActionOne','args'=>$args));
대신 제가 할 수 있는 일은:
$myClass->doActionOne($args);
하드코드로 하기 위해서는 많은 복제가 필요합니다(이 예는 코드와 매우 유사합니다).
public function doActionOne($array)
{
$this->args = $array;
$name = __FUNCTION__;
$this->response = $this->executeCoreCall("APIService.{$name}");
}
public function doActionTwo($array)
{
$this->args = $array;
$name = __FUNCTION__;
$this->response = $this->executeCoreCall("APIService.{$name}");
}
public function doActionThree($array)
{
$this->args = $array;
$name = __FUNCTION__;
$this->response = $this->executeCoreCall("APIService.{$name}");
}
protected function executeCoreCall($service)
{
$cURL = new \cURL();
return $cURL->('http://3rdparty.api.com?service='.$service.'&apikey='.$this->api.'&'.http_build_query($this->args))
->getResponse();
}
인 '마법'으로__call()
동적 방법으로 모든 서비스에 액세스할 수 있습니다.
public function __call($name, $arguments)
{
$this->args = $arguments;
$this->response = $this->executeCoreCall("APIService.{$name}");
return $this;
}
데이터 반환을 위한 이 동적 호출의 이점은 벤더가 다른 서브 서비스를 추가할 경우 클래스에 다른 메서드를 추가하거나 확장 클래스를 만들 필요가 없다는 것입니다.이 될지는 , , 「이것」의 「이것」의 「이것」의 「이것」의 「이것」의 「이것」의 「이것」의 「이것」의 「이것」을 .__set
,__get
,__call
주요 기능은 데이터 반환이기 때문에 검토 대상이 될 수 있습니다.
편집:
공교롭게도 글을 올린 지 며칠 만에 본 시나리오의 윤곽이 그대로 드러났습니다.제가 언급한 API는 아니지만 메서드의 적용은 동일합니다.
업데이트: 이 답변은 사용하지 마십시오.배우는 동안 발견한 매우 멍청한 코드입니다.그냥 플레인 게터랑 세터를 쓰면 훨씬 좋아요.
보통 이 변수 이름을 함수 이름으로 사용하고 옵션 파라미터를 해당 함수에 추가합니다.옵션 파라미터가 호출자에 의해 채워지면 해당 파라미터를 속성으로 설정하고 $this object(체인)를 반환합니다.또, 발신자에 의해 지정되지 않은 옵션 파라미터는 발신자에게만 속성을 반환합니다.
예:
class Model
{
private $propOne;
private $propTwo;
public function propOne($propVal = '')
{
if ($propVal === '') {
return $this->propOne;
} else {
$this->propOne = $propVal;
return $this;
}
}
public function propTwo($propVal = '')
{
if ($propVal === '') {
return $this->propTwo;
} else {
$this->propTwo = $propVal;
return $this;
}
}
}
언급URL : https://stackoverflow.com/questions/4478661/getter-and-setter
'IT' 카테고리의 다른 글
Intelij 코드 포맷, 새 줄의 Java 주석 (0) | 2022.10.29 |
---|---|
JS를 사용하여 HTML 문자열 구문 분석 (0) | 2022.10.29 |
MySQL의 utf8mb4와 utf8 문자 집합의 차이점은 무엇입니까? (0) | 2022.10.29 |
Java의 마커 인터페이스? (0) | 2022.10.29 |
MySQL 뷰에 데이터를 삽입할 수 있습니까? (0) | 2022.10.29 |