Геттер и сеттер?

203

Я не PHP-разработчик, поэтому мне интересно, если в PHP более популярно использовать явные методы получения / установки, в чистом стиле ООП, с закрытыми полями (как мне нравится):

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
Попробовав код из ответов, я использовал код, который вы используете в вопросе. Как грустно :-(
13
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, это всего лишь пример. Очень очень дурацкий пример для мощного ресурса.
Дэвис Пейшото
10
Это не совсем сеттер и геттер. Обычно для каждого свойства мне нужна разная реализация геттера!
13
79
Пожалуйста, не делайте: с помощью магических методов вы потеряете почти все функции, связанные с качеством, во многих IDE (даже vim): автозаполнение, явное наследование PHP, быстрая интерпретация PHP и полезная генерация и вывод PHPDoc. ср stackoverflow.com/a/6184893/490589
Ронан
113

Зачем использовать геттеры и сеттеры?

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

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

Wiliam
источник
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
В статье не сказано « нет », а написано «наивные сеттеры и геттеры».
Бретт Санторе
13
Можно с уверенностью предположить, что статья, написанная Google с заголовком «Советы по повышению производительности PHP», НЕ предназначена для того, чтобы предлагать хороший стиль кодирования, но быстрое выполнение кода. Глава, которая имеет дело с установщиками и получателями, помечена как «Избегайте написания наивных установщиков и получателей», и пример кода именно такой: Наивный. Он устанавливает и получает только переменную без какой-либо проверки. Этот вид сеттера / геттера бесполезен. Выполнение проверки внутри установщика (просто используйте подсказку типа для аргумента метода) сделает полезными установщики / получатели, потому что теперь ваш код ЗНАЕТ, с чем он имеет дело.
Свен
3
это все равно что сказать, что встроенный стиль лучше. конечно производительность лучше, но лучше ли код? В любом случае, я не знал, что инженеры Google используют php
Клаудиу Крянгэ,
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) также работает, но только при доступе к свойству, которое имеет более низкую видимость, чем текущая область. Он может легко вызвать головную боль при попытке отладки, если он не используется должным образом.

netcoder
источник
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)

kalsdas

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;
    }
}
J-Роу
источник
2
@ krzysztof-przygoda: «Волшебные методы» всегда идут с ценой. Они должны использовать рекурсию, property_exists(get_class($this), $name)а рекурсия медленная. Есть способ у смягчить это с помощью кэширования, но он все равно будет медленнее, чем создание методов получения и установки вручную. Я только написал это как альтернативу. Я на самом деле не рекомендую использовать «магические методы». Дополнительное время создания геттеров и сеттеров обычно незначительно.
J-Rou
7

В дополнение к и без того отличным и уважаемым ответам здесь я хотел бы остановиться на PHP без установщиков / получателей.

В PHP нет синтаксиса геттера и сеттера . Он предоставляет подклассные или магические методы, позволяющие «перехватывать» и переопределять процесс поиска свойств, как указал Дэйв .

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

Производительность Каждая ненужная функция, возникающая в результате принудительного использования 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придерживаться схемы именования actionname + 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

Готов!

Joas
источник
Слишком много шаблонов. Представьте, что это все в каждом классе. Избегайте ИМО
DarkNeuron
PHP не поддерживает геттеры и сеттеры по тем же причинам, о которых вы упомянули. Любая реализация этого типа сильно влияет на производительность серверного скрипта.
Джоас
Я думаю, что это идет вразрез с «частной» собственностью. Вы инкапсулируете их, но также разрешаете прямой доступ.
Корай Кюпе
@ KorayKüpe, только если определен геттер. Я часто использую эту инкапсуляцию (со многими улучшениями), и она отлично работает. Вы также можете расширить класс и легко использовать его во всем коде.
Джоас
5

Ну, PHP имеет магические методы __get, __set, __issetи __unset, всегда начало. Увы, правильные (понимаете?) Свойства ОО - это больше, чем магические методы. Основная проблема с реализацией PHP заключается в том, что магические методы вызываются для всех недоступных свойств. Это означает, что вы должны повторять себя (например, вызывая property_exists ()) в магических методах, когда определяете , действительно ли name является свойством вашего объекта. И вы не можете решить эту общую проблему с базовым классом, если все ваши классы не наследуются от ie. 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» и «fee».
Вы также можете использовать этот «белый список» для назначения пользовательских имен для доступа к вашим переменным.
Например,

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 () срабатывает при вызове недоступных методов в контексте объекта.

Sabaz
источник
Проблема со всеми этими «волшебными» решениями заключается в том, что они просто используют эти магические методы, потому что они есть, и они полезны, потому что заданная проблема является простой, общей. Когда вы выйдете из этого уровня общей проблемы, вы столкнетесь с особыми требованиями, которые не могут быть решены простым магическим методом, но потребуют очень сложного магического метода - или отдельных, закодированных сеттеров и геттеров.
Свен
2

Прочитав другие советы, я склонен сказать, что:

Как ОБЩЕЕ правило, вы не всегда будете определять сеттеры для ВСЕХ свойств, особенно «внутренних» (семафоры, внутренние флаги ...). Очевидно, что свойства только для чтения не будут иметь установщиков, поэтому некоторые свойства будут иметь только получатели; вот где __get () сокращает код:

  • определить __get () (магические глобальные геттеры) для всех одинаковых свойств,
  • сгруппируйте их в массивы так:
    • они будут иметь общие характеристики: денежные значения будут / могут подходить надлежащим образом, даты в определенном формате (ISO, США, международный) и т. д.
    • сам код может проверить, что с помощью этого магического метода читаются только существующие и разрешенные свойства.
    • всякий раз, когда вам нужно создать новое похожее свойство, просто объявите его и добавьте его имя в соответствующий массив, и все готово. Это намного быстрее, чем определение нового метода получения, возможно, с некоторыми строками кода, ПОВТОРЯЕМЫМИ снова и снова по всему коду класса.

Да! мы могли бы написать частный метод, чтобы сделать это, но, опять же, мы будем иметь МНОГИЕ объявленные методы (++ memory), которые в конечном итоге вызовут другой, всегда один и тот же метод. Почему бы просто не написать ОДИН метод, чтобы управлять ими всеми ...? [Ага! каламбур абсолютно предназначен! :)]

Магические сеттеры также могут реагировать ТОЛЬКО на определенные свойства, поэтому все свойства типа даты могут быть проверены на наличие недопустимых значений только одним методом. Если свойства типа даты были перечислены в массиве, их установщики могут быть легко определены. Просто пример, конечно. Есть слишком много ситуаций.

О читабельности ... Ну ... Это еще одна дискуссия: мне не нравится связываться с использованием IDE (на самом деле, я не использую их, они, как правило, говорят мне (и заставляют меня), как пиши ... а мне нравятся кодировки "красота"). Я склонен быть последовательным в отношении именования, поэтому мне достаточно использования ctags и пары других вспомогательных средств ... В любом случае: как только все эти магические сеттеры и геттеры завершены, я пишу другие сеттеры, которые слишком специфичны или «особенные» для быть обобщенным в методе __set (). И это охватывает все, что мне нужно о получении и настройке свойств. Конечно: не всегда есть общий язык, или есть несколько таких свойств, которые не стоят проблем при кодировании магического метода, а есть еще старая добрая традиционная пара сеттер / геттер.

Языки программирования - это всего лишь человеческие искусственные языки. Итак, у каждого из них есть своя собственная интонация или акцент, синтаксис и вкус, поэтому я не буду притворяться, что пишу код на Ruby или Python, используя тот же «акцент», что и Java или C #, и я не написал бы JavaScript или PHP, чтобы они напоминали Perl или SQL ... Используйте их так, как они предназначены.

Manuel
источник
1

Вообще говоря, первый способ в целом более популярен, потому что те, кто уже обладает знаниями в области программирования, могут легко перейти на PHP и выполнить работу объектно-ориентированным способом. Первый способ более универсален. Мой совет - придерживаться того, что проверено и верно на многих языках. Затем, когда и если вы будете использовать другой язык, вы будете готовы сделать что-то ( вместо того, чтобы тратить время на изобретение колеса ).

Энтони Ратледж
источник
0

Существует много способов создания исходного кода в соглашении netbeans. Это хорошо. Это делает мысли такими проще === ЛОЖЬ. Просто используйте традицию, особенно если вы не уверены, какое из свойств должно быть заключено в капсулу, а какое нет. Я знаю, что это код boi .... pla ..., но для отладки и многим другим он кажется лучшим и понятным. Не тратьте много времени на искусство, как делать простые добытчики и сеттеры. Вы не можете также реализовать некоторые шаблоны проектирования, такие как правило demeter и так далее, если вы используете магию. В конкретной ситуации вы можете использовать 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.

геттеры и сеттеры также полезны при расширении объектов. Например, предположим, что ваше приложение должно разрешать 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);
    }
}
FuzzyTree
источник
Однако много раз вам нужно проверять свойства вместе (а не только по отдельности). Я думаю, что разрешение «сеттеров» означает, что вы также не захватываете контекст. Проверка должна быть сделана на контекстной основе. Кроме того, вы будете вынуждены проверять какой-либо флаг «isValid» на каждом имеющемся у вас методе (и выполнять проверку, если она ложна). При этом сеттеры предоставляют полезный способ подсказки типа, например, когда у вас есть свойство, которое вы хотите использовать в качестве объекта значения (т. Е. Money).
программер
Я не понимаю, что вы имеете в виду, когда вынуждены проверять флаг "isValid"? Если единственный способ установить значения - это через установщики, которые выполняют проверку, то вы знаете, что данные действительны благодаря тому, что они были успешно установлены. Если вам нужно проверить свойства вместе, вы можете написать общий метод проверки, который вызывают установщики этих свойств.
FuzzyTree
Скажем, у вас есть класс сотрудников с setHiredи setHireDate. Нельзя допускать, чтобы кто-то назначал дату найма, не назначая сотрудника как наемного. Но вы никоим образом не обеспечили это. Если вы применяете его в одном из этих сеттеров, то вы устанавливаете порядок «установки», а для этого требуется больше чтения кода от разработчика. Затем, когда вы идете, чтобы сделать метод, подобный, $employee->promote($newPosition);вы должны проверить флаг, чтобы увидеть, была ли выполнена проверка, или предположить, что это не было сделано, и сделать это снова (избыточно).
программер
Вместо этого захватывайте взаимодействия. Возможно $employee->updateWorkStatus($hired, $hireDate);или если более продвинутый $employee->adminUpdate(\Employee\AdminUpdateDTO $dto);. Теперь вы можете проверить в нужном вам контексте и решить, нужна ли вообще дополнительная проверка.
программер
updateWorkStatus, по сути, является установочной функцией, которая устанавливает 2 вместо 1, но концепция та же. Это один из способов сделать это, но вы также можете поместить контекстную проверку в общий метод, который запускается только тогда, когда установлены все свойства, которые должны проверяться вместе, т.е. контекстная часть проверки будет вызываться как setHiredDate, так и setHired, но будет выполняться только если оба isset наняты и isset hiredDate были истиной.
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?

Rasclatt
источник
-2

Обновление: не используйте этот ответ, так как это очень глупый код, который я нашел во время изучения. Просто используйте простой метод получения и установки, это намного лучше.


Я обычно использую это имя переменной в качестве имени функции и добавляю необязательный параметр к этой функции, чтобы, когда этот необязательный параметр заполнялся вызывающей стороной, затем устанавливал его в свойстве и возвращал $ 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;
          }
     }
}
ajiyakin
источник
Теперь остается вопрос: как установить свойство для пустой строки? И как вы обнаруживаете, что установка свойства для пустой строки фактически не удалась и работала как получатель? Просто подумайте о формах HTML, отправляющих пустые поля в виде строк ... И нет: использование другого значения, такого как NULL, в качестве значения по умолчанию не решает проблему.
Свен