게터와 세터?


203

나는 PHP 개발자가 아니므로 PHP에서 개인 필드 (좋아하는 방식)와 함께 순수한 OOP 스타일로 명시적인 getter / setter를 사용하는 것이 더 인기가 있는지 궁금합니다.

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;
}

감사


7
답변에서 일부 코드를 시도한 후 질문에 사용중인 코드를 사용했습니다. 얼마나 슬픈 :-(
sumid

9
PHPstorm ...> 게터와 세터 생성. == 승리
DevDonkey

@DevDonkey 전혀 승리가 아닙니다. 구조화 된 데이터를 보유하려면 대신 배열을 사용하십시오. @ : Mark 이것은 개체의 목적이 아닙니다. 게터와 세터는 악하다 : yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Kubo2

답변:


222

당신이 사용할 수있는 PHP는 마법의 방법을 __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;
  }
}
?>

15
난 당신 말은 생각 __get하고 __set. 하나가 아닌 두 개의 밑줄이 있습니다. 다음은 페이지의 오른쪽 부분으로 직접 연결되는 링크입니다 : php.net/manual/en/… (정답은 +1)
Computerish

28
public유효성 검사 / 위생이없는 경우 속성에 대한 이점 은 무엇입니까?
KingCrunch

7
@ KingCrunch, 이것은 단지 예일뿐입니다. 강력한 리소스를위한 매우 더미 예제입니다.
Davis Peixoto

10
그것은 실제로 세터와 게터가 아닙니다. 일반적으로 각 속성마다 다른 getter 구현이 필요합니다!
sumid

79
하지 말아야 할 것 : 매직 메소드를 사용하면 자동 완성, 명시 적 PHP 상속, 빠른 PHP 해석 및 유용한 PHPDoc 생성 및 출력 등 많은 IDE (심지어 vim)에서 거의 모든 품질 관련 기능을 잃게됩니다. cf. stackoverflow.com/a/6184893/490589
Ronan

113

게터와 세터를 사용하는 이유는 무엇입니까?

  1. 확장 성 : 프로젝트 코드에서 모든 var 할당을 검색하는 것보다 게터를 리팩터링하는 것이 더 쉽습니다.
  2. 디버깅 : setter 및 getter에 중단 점을 둘 수 있습니다.
  3. Cleaner : 매직 기능은 적은 쓰기에는 좋은 솔루션이 아니며 IDE는 코드를 제안하지 않습니다. 빠른 쓰기 게터를위한 템플릿을 더 잘 사용하십시오.

직접 할당 및 게터 / 세터


7
@property를 사용하면 IDE에서 코드를 제안합니다 (PhStorm 7으로 테스트)
Alex2php

41

Google은 이미 PHP 최적화에 대한 가이드를 발표했으며 그 결론은 다음과 같습니다.

Getter 및 Setter 없음 PHP 최적화

그리고 마술 방법을 사용 해서는 안됩니다 . PHP의 경우 Magic Method는 사악합니다. 왜?

  1. 그들은 디버깅하기 어렵다.
  2. 성능에 부정적인 영향을 미칩니다.
  3. 더 많은 코드를 작성해야합니다.

PHP는 Java, C ++ 또는 C #이 아닙니다. PHP는 다르며 다른 역할을합니다.


10
나는 그 생각에 동의하는 경향이있다. 그 $dog->name = 'fido'보다 낫다 $dog->setName('fido'). 실제로 속성을 변경하는 경우 (예 : $dog->increaseAge(1)필요한 유효성 검사를 수행하고 해당 속성을 변경하는 방법을 만들 수 있습니다. 그러나 모든 작업에서 실제로 그러한 의미에서 변경이 필요한 것은 아닙니다.
Charlie Schliesser 2016.

11
이 기사 " 하지 않는다 " 라고 말하지 않고 '순진한 세터와 게터'라고 말합니다.
Brett Santore


13
"PHP 성능 팁"이라는 제목을 가진 Google이 작성한 기사는 좋은 코딩 스타일을 제안하는 것이 아니라 빠른 코드 실행을 의미한다고 가정하는 것이 안전합니다. setter 및 getter를 다루는 장에는 "순진한 setter 및 getter 작성 금지"라는 레이블이 붙어 있으며 코드 예제는 정확히 다음과 같습니다. Naive. 유효성 검사없이 변수를 설정하고 가져옵니다. 이런 종류의 setter / getter는 쓸모가 없습니다. setter 내에서 유효성 검사를 수행하면 (메소드 인수에 대한 유형 힌트 만 사용함) 이제 setter / getter가 유용하므로 코드에서 처리하는 내용을 알고 있기 때문입니다.
Sven

3
이것은 인라인 스타일링이 더 좋다고 말하는 것과 같습니다. 물론 성능은 더 좋지만 더 나은 코드입니까? 나는 구글 엔지니어가 어쨌든 PHP를 사용하는지 몰랐다
Claudiu Creanga

13

캡슐화는 모든 OO 언어에서 중요하며 인기는 그것과 관련이 없습니다. PHP와 같이 동적으로 유형이 지정된 언어에서는 setter를 사용하지 않고 속성이 특정 유형인지 확인하는 방법이 거의 없기 때문에 특히 유용합니다.

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)를 사용하는 것도 가능하지만 현재 범위보다 가시성이 낮은 속성에 액세스 할 때만 액세스 할 수 있습니다. 제대로 사용하지 않으면 디버그하려고 할 때 쉽게 두통을 줄 수 있습니다.


7
게터와 세터는 캡슐화를 가져 오지 않습니다. 캡슐화 == 객체는 외부에주는 대신 자체 데이터로 무언가를 수행합니다. Getter와 Setter는 PHP와 같이 동적으로 유형이 지정된 언어로 유형을 시행하는 도구가 아닙니다.
smentek

14
@ smentek : 캡슐화의 절반 이상이 명확하게 누락되었습니다.
netcoder

2
찾는 사람을 위해 이것에 대한 업데이트로, PHP 7.4는 유형 속성 지원과 함께 제공됩니다. 따라서 첫 번째 예제에서 $bar로 선언 할 수 있습니다 int. wiki.php.net/rfc/typed_properties_v2
Kevin

7

__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;
    }
}

2
@ krzysztof-przygoda :이 "매직 방법"에는 항상 가격이 붙어 있습니다. 재귀를 사용해야 property_exists(get_class($this), $name)하며 재귀가 느립니다. 캐시를 사용하여이를 완화 할 수있는 방법이 있지만 여전히 손으로 게터와 세터를 만드는 것보다 속도가 느립니다. 나는 이것을 대안으로 썼다. 실제로 "Magic Methods"를 사용하지 않는 것이 좋습니다. 게터와 세터를 만드는 추가 시간은 일반적으로 중요하지 않습니다.
J-Rou

7

여기에 이미 훌륭하고 존경받는 답변 외에도 setter / getter가없는 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
    "

    이 경우 generatelatexactionname + methodname의 이름 지정 체계를 준수합니다.

  • 특별하고 명백한 경우

    $dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated()
    $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()

참고 : PHP는 getter / setter 구문을 구현하지 않기로 선택했습니다. 나는 게터 / 세터가 일반적으로 나쁘다고 주장하지 않는다.


6
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

준비된!


상용구가 너무 많습니다. 이 물건이 모든 수업에 있다고 상상해보십시오. IMO 피하기
DarkNeuron

PHP는 언급 한 것과 같은 이유로 게터와 세터를 지원하지 않습니다. 이 유형의 모든 구현은 서버 측 스크립트의 성능에 심각한 영향을 미칩니다.
joas

나는 이것이 '개인'속성에 위배된다고 생각합니다. 캡슐화 할뿐만 아니라 직접 액세스 할 수도 있습니다.
Koray Küpe

게터가 정의 된 경우에만 @ KorayKüpe. 나는이 캡슐화를 많이 사용하고 (많은 개선 사항이 있음) 완벽하게 작동합니다. 클래스를 확장하여 모든 코드에서 쉽게 사용할 수 있습니다.
joas

5

음, PHP는 마법 방법을 가지고 __get, __set, __isset__unset항상 시작이다. 아아 적절한 (얻을까요?) OO 속성은 마술 방법 이상입니다. PHP 구현의 주된 문제점은 접근 할 수없는 모든 속성에 대해 마법 메서드가 호출된다는 것 입니다. 즉, 이름 이 실제로 객체의 속성 인지 확인할 때 마술 메서드에서 자신을 반복해야합니다 (예 : property_exists () 호출) . 그리고 모든 클래스가 ie에서 상속하지 않으면 기본 클래스 로이 일반적인 문제를 실제로 해결할 수 없습니다. PHP에는 다중 상속이 없기 때문에 ClassWithProperties.

반면에 파이썬의 새로운 스타일 클래스는 property()모든 속성을 명시 적으로 정의 할 수있게합니다. C # 에는 특별한 구문이 있습니다.

http://en.wikipedia.org/wiki/Property_(programming)


1
property_exists, class_vars 또는 array_key_exists 호출 (즉, 속성이 실제로 존재하는지 확인)은 런타임 치명적 오류를 피하기위한 단계입니다. 모호하지 않은 것이 코딩에서 반복되는 것과 같은지 확실하지 않습니다.
Davis Peixoto

1
그럴 수 있지. 그러나 파이썬과 C #에서는이 반복이 필요하지 않습니다. 나는 그것이 힘이라고 생각합니다.
Emanuel Landeholm

4

매직 메소드 __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];
    }
}

이제 "foo"와 "fee"만 가져 오거나 설정할 수 있습니다.
이 "화이트리스트"를 사용하여 var에 액세스 할 사용자 정의 이름을 지정할 수도 있습니다.
예를 들어

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 () 은 객체 컨텍스트에서 접근 할 수없는 메소드를 호출 할 때 트리거됩니다.


이러한 모든 "마법"솔루션의 문제점은 이러한 마법 방법이 있기 때문에 단순히 사용하는 것입니다. 요청 된 문제가 단순하고 일반적인 방법이기 때문에 유용합니다. 이 수준의 일반적인 문제를 벗어나면 간단한 마술 방법으로는 해결할 수 없지만 매우 복잡한 마술 방법 또는 개별 코드화 된 세터 및 게터가 필요한 특정 요구 사항이 발생합니다.
Sven

2

다른 조언을 읽은 후에는 다음과 같이 말하고 싶습니다.

A와 GENERIC 규칙, 당신은 항상에 대한 setter를 정의하지 않습니다 ALL의 (... 세마포어, 내부 플래그) 속성, 특별히 "내부"사람을. 읽기 전용 속성에는 setter가 없으므로 일부 속성에는 getter 만 있습니다. 그것이 __get ()이 코드를 축소하는 곳입니다.

  • 비슷한 모든 속성에 대해 __get () (매직 글로벌 게터)을 정의하십시오.
  • 배열로 그룹화하십시오.
    • 공통적 인 특징을 공유합니다 : 화폐 가치는 형식이 올바르거나 특정 레이아웃의 날짜 (ISO, US, Intl.) 등입니다.
    • 코드 자체는이 마법적인 방법을 사용하여 기존 속성과 허용 속성 만 읽고 있는지 확인할 수 있습니다.
    • 비슷한 속성을 새로 만들어야 할 때마다 선언하고 적절한 배열에 이름을 추가하면됩니다. 그것은 클래스 코드 전체에 반복적으로 반복되는 몇 줄의 코드로 새로운 getter를 정의하는 것보다 훨씬 빠릅니다 .

예! 우리는 그렇게하기 위해 개인 메소드를 작성할 수 있지만, 다시 말하지만, 항상 동일한 메소드를 호출하는 많은 메소드 (++ 메모리)가 선언됩니다. 왜 그들 모두지배하기 위해 SINGLE 메소드를 작성하지 않습니까? [네! 절대적으로 의도 된 말장난! :)]

매직 세터는 특정 속성에만 응답 할 수 있으므로 한 가지 방법만으로 모든 날짜 유형 속성을 유효하지 않은 값에 대해 선별 할 수 있습니다. 날짜 유형 특성이 배열에 나열되면 해당 세터를 쉽게 정의 할 수 있습니다. 물론 예입니다. 상황이 너무 많습니다.

가독성에 대해 ... 글쎄 ... 그것은 또 다른 논쟁입니다. 저는 IDE 사용에 얽매이고 싶지 않습니다 (사실, 나는 그것들을 사용하지 않습니다, 그들은 나에게 방법을 알려주고 강요 하는 경향이 있습니다 ) 쓰기 ... 그리고 나는 "아름다움"을 코딩하는 것을 좋아합니다.) 나는 이름에 대해 일관성을 유지하는 경향이 있으므로 ctags와 몇 가지 다른 보조 도구를 사용하면 충분합니다 ... 어쨌든 :이 마술 세터와 게터가 모두 끝나면 다른 세터를 너무 구체적이거나 "특별한" __set () 메소드에서 일반화되어야합니다. 그리고 그것은 속성을 얻고 설정하는 데 필요한 모든 것을 다룹니다. 물론 : 항상 공통점이있는 것은 아니며, 마법적인 방법을 코딩하는 데 어려움을 겪을 가치가없는 몇 가지 속성이 있으며, 여전히 기존의 전통적인 세터 / 게터 쌍이 있습니다.

프로그래밍 언어는 인간 인공 언어입니다. 따라서 각각의 고유 한 억양이나 악센트, 구문 및 풍미가 있으므로 Java 또는 C #과 동일한 "액센트"를 사용하여 Ruby 또는 Python 코드를 작성하는 척하지 않으며 JavaScript 또는 PHP를 작성하여 닮지 않습니다. Perl 또는 SQL ... 사용하는 방식대로 사용하십시오.


1

일반적으로, 첫 번째 방법은 사전 프로그래밍 지식이있는 사람들이 PHP로 쉽게 전환하고 객체 지향 방식으로 작업을 수행 할 수 있기 때문에 전체적으로 더 인기가 있습니다. 첫 번째 방법은 더 보편적입니다. 저의 조언은 많은 언어에서 시도되고 진실 된 것을 고수하는 것입니다. 그런 다음 언제 다른 언어를 사용하면 무언가를 성취 할 준비가됩니다 ( 바퀴를 재창조하는 데 시간을 소비하는 대신 ).


0

netbeans-convention에서 소스 코드를 작성하는 방법에는 여러 가지가 있습니다. 이거 좋은데. 그렇게 쉽게 생각할 수 있습니다 === FALSE. 어떤 속성을 캡슐화해야하는지, 어떤 속성을 캡슐화하지 않아야하는지 확실하지 않은 경우, 특히 traditionalel을 사용하십시오. 나는 그것이 boi .... pla ... 코드라는 것을 알고 있지만 디버깅 작업과 다른 많은 사람들에게는 그것이 더 좋고 명확한 방법이라고 생각합니다. 간단한 게터와 세터를 만드는 방법에 대해 thousend of arts와 많은 시간을 보내지 마십시오. 마법을 사용하는 경우 demeter-rule 등과 같은 일부 디자인 패턴을 구현할 수 없습니다. 특정 상황에서는 magic_calls를 사용하거나 작고 빠르고 명확한 솔루션을 사용할 수 있습니다. 물론 이런 방식으로 디자인 패턴에 대한 솔루션을 만들 수는 있지만 왜 생활을 더 어렵게 만드는가?


0

값 검증 + 포맷 / 파생

세터를 사용하면 데이터의 유효성을 검사하고 게터를 사용하여 데이터를 형식화하거나 파생시킬 수 있습니다. 개체를 사용하면 데이터와 해당 유효성 검사 및 서식 코드를 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;
    }
}

설정되는 값이 유효한지 확인하고 싶을 것입니다

  • 유효한 날짜
  • 미래에는 없다

또한 애플리케이션 전체에서 (또는 해당 사안의 여러 애플리케이션에서)이 유효성 검증을 수행하고 싶지 않습니다. 대신 멤버 변수를 보호 또는 비공개로 설정하고 (세터를 유일한 액세스 포인트로 만들기 위해) 세터에서 검증하는 것이 더 쉽습니다. 응용 프로그램에서 개체를 가져 왔으며 더 많은 유효성 검사를 추가하려는 경우 한 곳에서 추가 할 수 있습니다.

당신은 같은 멤버 변수의 예에서 작동 여러 포매터 추가 할 수 있습니다 getAge()getDaysUntilBirthday()당신은에 구성 형식을 적용 할 수 있습니다 getBirthDate()지역에 따라. 따라서 나는와 혼합 $date->getAge()하는 대신 게터를 통해 값에 지속적으로 액세스하는 것을 선호합니다 $date->birth_date.

getter 및 setter는 객체를 확장 할 때도 유용합니다. 예를 들어, 어떤 곳에서는 150 년 이상의 생년월일을 허용해야하지만 다른 곳에서는 그렇지 않다고 가정 해 봅시다. 코드를 반복하지 않고 문제를 해결하는 한 가지 방법은 BirthDate객체 를 확장 하고 추가 검증을 setter에 넣는 것입니다.

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);
    }
}

그러나 여러 번 속성을 함께 검증해야합니다 (단지 개별적이 아닌). "세터"를 허용하면 컨텍스트를 캡처하지 않는 것입니다. 유효성 검사는 상황에 따라 수행해야합니다. 또한 모든 메소드에서 "isValid"플래그를 확인해야합니다 (잘못된 경우 유효성 검사 수행). 즉, 세터는 가치 객체 (예 : 돈)가되고 싶은 속성이있을 때와 같이 유형 힌트에 유용한 방법을 제공합니다.
prograhammer

"isValid"플래그를 확인해야한다는 의미를 이해하지 못합니까? 값을 설정하는 유일한 방법이 유효성 검사를 수행하는 세터를 통하는 것이라면 데이터가 성공적으로 설정 되었기 때문에 데이터가 유효하다는 것을 알 수 있습니다. 특성을 함께 유효성 검증해야하는 경우 해당 특성의 설정자가 호출하는 공통 유효성 검증 방법을 작성할 수 있습니다.
FuzzyTree

당신이 직원 클래스가 있다고 가정 setHired하고 setHireDate. 직원을 고용 된 사람으로 설정하지 않고 고용 날짜를 설정하는 것은 유효하지 않습니다. 그러나 이것을 시행 할 방법은 없습니다. 이 세터 중 하나에 적용하면 "설정"순서를 강제하는 것보다 개발자가 알아야 할 더 많은 코드 읽기가 필요합니다. 그런 다음과 같은 방법을 수행 할 때 $employee->promote($newPosition);유효성 검사가 수행되었는지 또는 수행되지 않았다고 가정하고 플래그를 확인해야합니다 (중복).
prograhammer

대신, 상호 작용을 포착하십시오. 아마도 $employee->updateWorkStatus($hired, $hireDate);또는 더 발전된 경우 $employee->adminUpdate(\Employee\AdminUpdateDTO $dto);. 이제 필요한 컨텍스트에서 유효성을 검사하고 추가 유효성 검사가 필요한지 결정할 수 있습니다.
prograhammer

updateWorkStatus는 기본적으로 1 값 대신 2를 설정하는 세터 함수이지만 개념은 동일합니다. 이를 수행하는 한 가지 방법이지만 컨텍스트 유효성 검사를 함께 검증해야하는 모든 특성이 설정된 경우에만 실행되는 공통 메소드에 컨텍스트 유효성 검증을 넣을 수도 있습니다. 즉 유효성 검증의 컨텍스트 부분이 setHiredDate 및 setHired에 의해 호출되지만 실행 만 가능합니다. isset hired와 isset hiredDate가 모두 true 인 경우
FuzzyTree

0

이 게시물에 대해 구체적으로하지 않습니다 __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는 아니지만 메소드 적용은 동일합니다.

API를 올바르게 사용하고 있습니까?


-2

업데이트 : 이것은 내가 배우는 동안 찾은 매우 멍청한 코드 이므로이 답변을 사용하지 마십시오. 일반 게터와 세터를 사용하면 훨씬 좋습니다.


나는 일반적으로 변수 이름을 함수 이름으로 사용하고 선택적 매개 변수를 해당 함수에 추가하여 호출자가 선택적 매개 변수를 채울 때 속성으로 설정하고 $ this 객체 (체인)를 반환 한 다음 선택적 매개 변수가 발신자, 방금 발신자에게 속성을 반환합니다.

내 예 :

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;
          }
     }
}

이제 질문이 남아 있습니다 : 속성을 빈 문자열로 어떻게 설정합니까? 그리고 속성을 빈 문자열로 설정하는 것이 실제로 실패하고 getter로 작동했다는 것을 어떻게 감지합니까? 빈 필드를 문자열로 전송하는 HTML 양식에 대해 생각해보십시오. 아니요 : 기본값으로 NULL과 같은 다른 값을 사용해도 문제가 해결되지 않습니다.
Sven
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.