Геттер і сетер?


203

Я не розробник PHP, тому мені цікаво, чи в PHP популярніше використовувати явні геттери / сетери, в чистому стилі 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;
}

Дякую


7
Спробувавши якийсь код із відповідей, я використав код, який ви використовуєте у питанні. Як сумно :-(
Суди

9
PHPstorm ... генерувати> геттери та сетери. == win
DevDonkey

@DevDonkey Зовсім не виграш. Для зберігання структурованих даних використовуйте масиви замість цього. @: Позначити Це не те, для чого є об'єкти. Геттери та сетери - це зло: 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 для правильної відповіді)
Комп'ютер

28
Яка вигода від publicнерухомості, якщо немає перевірки / санітарії?
KingCrunch

7
@KingCrunch, це лише приклад. Дуже дуже підступний приклад для потужного ресурсу.
Девіс Пейксото

10
Це насправді не сетер та геттер. Як правило, мені потрібно для кожної властивості різне виконання getter!
сумід

79
Будь ласка, не: За допомогою магічних методів ви ЗБУДИТЕ майже всі функції, пов’язані з якістю, у багатьох IDE (навіть vim): автоматичне завершення, явне успадкування PHP, швидка інтерпретація PHP та корисна генерація та вихід PHPDoc. пор. stackoverflow.com/a/6184893/490589
Ронан

113

Навіщо використовувати геттери та сетери?

  1. Масштабованість : простіше отримати рефактор, ніж шукати всі завдання в коді проекту.
  2. Налагодження : Ви можете ставити точки перерви у встановниках та на геттерах.
  3. Очисник : Магічні функції не є гарним рішенням для того, щоб писати менше, ваш IDE не запропонує код. Краще використовувати шаблони для швидкозаписуючих.

пряме призначення та геттери / сетери


7
Якщо ви використовуєте @property, ваш IDE запропонує код (перевірений PhpStorm 7)
Alex2php

41

Google вже опублікував посібник з оптимізації PHP, і висновок:

Ніяких геттерів та налаштувань Оптимізація PHP

І ні, ви не повинні використовувати магічні методи . Для PHP Магічний метод - це зло. Чому?

  1. Їх важко налагодити.
  2. Відбувається негативний вплив на продуктивність.
  3. Вони вимагають написати більше коду.

PHP - це не Java, C ++ або C #. PHP відрізняється і грає з різними ролями.


10
Я схильний погодитися з цією ідеєю; що $dog->name = 'fido'краще $dog->setName('fido'). Коли насправді видозмінюється властивість (напр .: $dog->increaseAge(1)я можу створити метод, який робить необхідну перевірку та мутує цю властивість. Але не всі дії дійсно потребують мутації в цьому сенсі.
Чарлі Шліссер,

11
У статті не сказано " не треба ", а "наївні сеттери".
Бретт Санторе

1
Воно відроджено: web.archive.org/web/20140625191431/https://…

13
Можна впевнено припустити, що стаття, написана Google, що має заголовок "Поради щодо продуктивності PHP", НЕ призначена для того, щоб запропонувати хороший стиль кодування, а швидке виконання коду. Розділ, який стосується сеттерів та геттерів, позначений "Уникайте написання наївних сетерів та геттерів", а приклад коду - саме такий: Naive. Він встановлює та отримує просто змінну без будь-якої перевірки. ЦЕ вид сеттера / геттера марний. Проведення перевірки всередині сеттера (просто використовувати підказку типу для аргументу методу) зробить setters / getters корисними, тому що тепер ваш код знає, з чим він має справу.
Свен

3
це як би сказати, що вбудований стиль в лінійці краще. звичайно, продуктивність краща, але чи краще код? Я не знав, що інженери google все одно використовують php
Claudiu Creanga

13

Інкапсуляція важлива для будь-якої мови ОО, популярність тут нічого спільного. У динамічно набраних мовах, як 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) також працює, але лише при доступі до ресурсу, який має меншу видимість, ніж поточний діапазон, може отримати доступ. Він може легко доставити вам головні болі при спробі налагодження, якщо він не використовується належним чином.


7
Геттери і сетери не приносять капсулювання. Інкапсуляція == об'єкти роблять щось із власними даними, а не видають їх назовні. Геттери та сетери - це не інструмент для примусового використання типу в динамічно набраних мовах, як PHP.
smentek

14
@smentek: Вам явно не вистачає принаймні половини того, що є насправді інкапсуляцією.
netcoder

2
Як оновлення цього для всіх, хто шукає, PHP 7.4 поставиться із типовою підтримкою властивостей. Таким чином, ви можете оголосити $barяк intперший приклад: wiki.php.net/rfc/typed_properties_v2
Кевін

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)а рекурсія повільна. Існує спосіб y пом'якшити це за допомогою кешування, але це все ще буде повільніше, ніж створювати геттери та сетери вручну. Я писав це лише як альтернативу. Я фактично не рекомендую використовувати "Чарівні методи". Додатковий час створення геттерів та сеттерів, як правило, незначний.
J-Rou

7

На додаток до вже чудових і шанованих відповідей тут, я хотів би поширитись на PHP, не маючи сеттерів / гетерів.

У PHP немає синтаксису getter та setter . Він надає підкласові або магічні методи, що дозволяють "підключити" і перекрити процес пошуку властивостей, на що вказував Дейв .

Магія дозволяє нам лінивим програмістам робити більше з меншим кодом за той час, коли ми активно займаємось проектом і знаємо його інтимно, але зазвичай за рахунок читабельності.

Продуктивність Кожна непотрібна функція, що виникає внаслідок примусового кодування архітектури коду в Getter / Setter в PHP, включає власний стек-кадр пам'яті після виклику і витрачає цикли процесора.

Читання: У базі коду виникають здуті рядки коду, що впливає на кодову навігацію, оскільки більше 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буде дотримуватися схема імен імені action name + namename

  • особливі, очевидні випадки

    $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

Я думаю, це суперечить "приватним" властивостям. Ви інкапсулюєте їх, але також дозволяєте отримати доступ безпосередньо.
Корай Кюпе

@ KorayKüpe, лише якщо визначено геттер. Я дуже часто використовую цю інкапсуляцію (з багатьма вдосконаленнями), і вона працює чудово. Ви також можете розширити клас і легко використовувати його у всьому коді.
joas

5

Ну, PHP має магічні методи __get, __set, __issetі __unset, завжди початок. На жаль, властивості OO - це більше, ніж магічні методи. Основна проблема реалізації PHP полягає в тому, що магічні методи викликаються для всіх недоступних властивостей. Що означає, що вам доведеться повторити себе (наприклад, зателефонувавши у властивості магічних методів property_exists ()), коли визначаєте, чи власне ім'я є власністю вашого об'єкта. І ви не можете реально вирішити цю загальну проблему з базовим класом, якщо всі ваші класи не успадковують, тобто. ClassWithProperties, оскільки PHP не вистачає багаторазового успадкування.

На відміну від нових класів стилів Python дає вам property(), що дозволяє чітко визначити всі свої властивості. C # має спеціальний синтаксис.

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


1
Виклик property_exists, class_vars або array_key_exists (тобто перевірка наявності власності насправді) - лише крок, щоб уникнути фатальної помилки під час виконання. Я не впевнений, що не бути розбірливим - це те саме, що повторюватися в кодуванні.
Девіс Пейксото

1
Досить справедливо. Але в Python та C # це повторення не потрібне. Я думаю, що це сила.
Емануель Ландегольм

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" та "honorar".
Ви також можете використовувати цей "білий список", щоб призначити власні імена для доступу до ваших змін.
Наприклад,

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 () спрацьовує, коли викликає недоступні методи в контексті об'єкта.


Проблема всіх цих "магічних" рішень полягає в тому, що вони просто використовують ці магічні методи, оскільки вони є, і вони корисні, оскільки задана проблема є простою, загальною. Після того, як ви вийдете з цього рівня загальної проблеми, ви зіткнетесь з конкретними вимогами, які неможливо вирішити простим магічним методом, але потребуватиме дуже складного магічного методу - або окремих, кодованих сеттерів та геттерів.
Свен

2

Прочитавши інші поради, я схильний сказати, що:

Як правило GENERIC , ви не завжди визначаєте сетерів для ВСІХ властивостей, особливо "внутрішніх" (семафорів, внутрішніх прапорів ...). Очевидно, що властивості лише для читання не матимуть сеттерів, тому деякі властивості матимуть лише getters; ось де __get () приходить, щоб зменшити код:

  • визначити __get () (магічні глобальні гетери) для всіх тих властивостей, які однакові,
  • згрупуйте їх у масиви так:
    • вони поділять загальні характеристики: грошові величини будуть / можуть виходити належним чином відформатованими, датами у визначеному макеті (ISO, US, Intl.) тощо.
    • сам код може перевірити, чи читаються лише існуючі та дозволені властивості за допомогою цього магічного методу.
    • всякий раз, коли вам потрібно створити нову подібну властивість, просто оголосіть її та додайте її ім'я у відповідний масив, і це зроблено. Таким чином швидше, ніж визначення нового геттера, можливо, з деякими рядками коду повторюються знову і знову по всьому коду класу.

Так! ми також можемо написати приватний метод для цього, але знову ж таки, у нас буде МНОГО оголошених методів (++ пам'яті), які в кінцевому підсумку викликають інший, завжди той самий, метод. Чому просто не написати єдиний метод, щоб керувати ними всіма ...? [так! каламбур абсолютно призначений! :)]

Магічні налаштування також можуть реагувати ТІЛЬКИ на конкретні властивості, тому всі властивості типу дати можуть бути перевірені проти недійсних значень лише одним методом. Якщо властивості типу дати були перелічені в масиві, їх сеттер можна легко визначити. Просто приклад, звичайно. буває занадто багато ситуацій.

Про читабельність ... Ну ... Це ще одна дискусія: мені не подобається прив'язуватися до використання IDE (насправді я не використовую їх, вони, як правило, говорять мені (і змушують мене), як це зробити пишіть ... і у мене є свої симпатії щодо кодування "краси"). Я схильний бути послідовним щодо імен, тому використання ctags та декількох інших посібників мені достатньо ... У будь-якому разі: як тільки всі ці магічні сеттери та геттери будуть виконані, я записую інші сетери, які є надто специфічними або "особливими" для бути узагальненим методом __set (). І це стосується всього, що мені потрібно про отримання та налаштування властивостей. Зрозуміло: не завжди існує спільної точки зору, або є така кількість властивостей, що не вартує клопотів із кодуванням магічного методу, і тоді ще є стара хороша традиційна пара сеттера та геттера.

Мови програмування - це лише такі: штучні мови людини. Отже, у кожного з них є своя інтонація чи акцент, синтаксис та аромат, тому я не буду робити вигляд, щоб написати код Ruby чи Python, використовуючи той самий "акцент", що і Java або C #, і не писав би JavaScript чи PHP, щоб вони нагадували Perl або SQL ... Використовуйте їх так, як вони призначені для використання.


1

Взагалі кажучи, перший спосіб є більш популярним загалом, оскільки ті, хто має попередні знання з програмування, можуть легко перейти до PHP та зробити роботу об'єктно-орієнтованою. Перший спосіб більш універсальний. Моя порада полягає в тому, щоб дотримуватися того, що випробувано і правдиво для багатьох мов. Тоді, коли і якщо ви використовуєте іншу мову, ви будете готові щось досягти ( замість того, щоб витрачати час на винахід колеса ).


0

Існує багато способів створення вихідного коду в netbeans-convention. Це добре. Це змушує думати, що таке полегшення === ЛЖА. Просто використовуйте традиціонель, особливо якщо ви не впевнені, яка з властивостей повинна бути інкапсульована, а яка - ні. Я знаю, це boi .... pla ... код, але для налагодження працює і багато інших думає, що це кращий, зрозумілий шлях. Не витрачайте багато часу з тисячами мистецтв, як зробити прості геттери та сетери. Ви не можете реалізувати занадто деякі шаблони дизайну, як правило деметера тощо, якщо ви використовуєте магію. У конкретній ситуації ви можете використовувати 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()залежності від регіону. Тому я віддаю перевагу послідовному доступу до значень через getters, а не змішуванню $date->getAge()з $date->birth_date.

Геттери і сетери також корисні при розширенні об'єктів. Наприклад, припустимо, що вашій заяві потрібно було дозволити дати народження 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);
    }
}

Однак багато разів потрібно перевіряти властивості разом (і не лише окремо). Я думаю, що дозволити "сетерам" означає, що ви також не захоплюєте контекст. Валідація повинна проводитися на контекстній основі. Крім того, ви будете змушені перевіряти деякий прапор "isValid" на кожному з ваших методів (і виконувати перевірку, якщо вона помилкова). Незважаючи на це, сеттери надають корисний спосіб підказки типу, наприклад, коли у вас є властивість, яке ви хочете бути об'єктом цінності (тобто гроші).
програмамер

Я не розумію, що ви маєте на увазі, змушені перевіряти прапор "isValid"? Якщо єдиний спосіб встановити значення - це сеттери, які виконують перевірку, то ви знаєте, що дані достовірні тим, що вони були успішно встановлені. Якщо вам потрібно перевірити властивості разом, ви можете написати загальний метод перевірки, який викликають сектори цих властивостей.
FuzzyTree

Скажіть, у вас є клас працівника з setHiredта setHireDate. Неправильно дозволяти комусь встановлювати дату найму, не встановлюючи працівника як найманого. Але немає жодного способу, як ви це застосували. Якщо ви застосовуєте його в одному з цих сетерів, тоді ви примушуєте порядок "налаштування", і це вимагає більше читання коду від розробника, щоб знати. Потім, коли ви йдете робити такий метод, як $employee->promote($newPosition);вам потрібно перевірити прапор, щоб побачити, чи було зроблено перевірку, чи припустити, що це не було зроблено, і повторіть це (зайве).
prograhammer

Натомість зафіксуйте взаємодії. Можливо, $employee->updateWorkStatus($hired, $hireDate);або якщо більш просунутий $employee->adminUpdate(\Employee\AdminUpdateDTO $dto);. Тепер ви можете перевірити необхідний контекст і вирішити, чи потрібна взагалі будь-яка додаткова перевірка.
prograhammer

updateWorkStatus - це по суті функція встановлення, яка встановлює 2 замість 1 значення, але концепція така ж. Це один із способів зробити це, але ви також можете помістити контекстну перевірку в загальний метод, який запускається лише тоді, коли всі властивості, які потрібно перевірити разом, встановлені, тобто контекстна частина перевірки буде викликана і setHiredDate, і setHired, але працюватиме лише якщо обидва розміщені набір і найманий дат були правдивими.
FuzzyTree

0

Це повідомлення не конкретно про __getі __setа __callщо та ж ідея методу виклику , за винятком. Як правило, я тримаюсь подалі від будь-яких магічних методів, які дозволяють перевантажуватись з причин, викладених у коментарях та дописах ТАКОЖ , я нещодавно наткнувся на сторонній API, який я використовую, який використовує SERVICE та SUB-SERVICE, наприклад :

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

Оновлення: Не використовуйте цю відповідь, оскільки це дуже німий код, який я знайшов, коли я вчуся. Просто використовуйте звичайний геттер і сетер, це набагато краще.


Зазвичай я використовую це ім'я змінної як ім'я функції, і додаю необов'язковий параметр до цієї функції, тож коли цей необов'язковий параметр заповнюється викликом, потім встановлюю його у властивість та повертаю $ цей об’єкт (ланцюжок), а потім, коли цей необов'язковий параметр не визначається абонент, я просто повертаю майно абоненту.

Мій приклад:

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

Тепер залишається питання: як встановити властивість до порожнього рядка? І як ви виявите, що встановлення властивості на порожній рядок насправді не вдалося і працювало як геттер? Подумайте лише про форми HTML, що надсилають порожні поля як рядки ... І ні: Використання іншого значення, такого як NULL, як значення за замовчуванням, не вирішує проблему.
Свен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.