Когда do / следует использовать __construct (), __get (), __set () и __call () в PHP?

Аналогичный вопрос обсуждается __construct , но я оставил его в своем названии для поиска людей, которые его находят.

По-видимому, __get и __set принимают параметр, который получает или задает переменную. Однако вы должны знать имя переменной (например, знаете, что возраст человека – это $ age вместо $ myAge). Поэтому я не вижу смысла, если вам нужно знать имя переменной, особенно если вы работаете с кодом, с которым вы не знакомы (например, с библиотекой).

Я нашел несколько страниц, которые объясняют __get() , __set() и __call() , но я до сих пор не понимаю, почему и когда они полезны.

Related of "Когда do / следует использовать __construct (), __get (), __set () и __call () в PHP?"

Эта страница , вероятно, будет полезна. (Обратите внимание, что то, что вы говорите, неверно – __set() принимает в качестве параметра как имя переменной, так и значение. __get() просто берет имя переменной).

__get() и __set() полезны в библиотечных функциях, где вы хотите предоставить общий доступ к переменным. Например, в классе ActiveRecord вы можете захотеть, чтобы люди имели доступ к полям базы данных в качестве свойств объекта. Например, в инфраструктуре Kohana PHP вы можете использовать:

 $user = ORM::factory('user', 1); $email = $user->email_address; 

Это достигается с помощью __get() и __set() .

Что-то подобное может быть выполнено при использовании __call() , т.е. вы можете обнаружить, когда кто-то вызывает getProperty () и setProperty () и обрабатывает соответственно.

__get (), __set () и __call () – это то, что PHP называет «магическими методами», который является прозвищем. Я думаю, что это немного глупо – я думаю, что «крючок» немного более уместен. Во всяком случае, я отвлекаюсь …

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

Однако есть стоимость – вызов, который вызывает их, примерно в 10 раз медленнее, чем вызов определенным данным.

Переопределение __get и __set может быть особенно полезно в основных классах. Например, если вы не хотите, чтобы ваш конфиг был перезаписан случайно, но все же хотел получить данные от него:

 class Example { private $config = array('password' => 'pAsSwOrD'); public function __get($name) { return $this->config[$name]; } } 

Еще одно полезное применение магических методов, особенно __get и __set и __toString – это шаблоны. Вы можете сделать свой код независимым от механизма шаблонов, просто написав простой адаптер, который использует магические методы. Если вы хотите перейти к другому движку шаблонов, просто измените эти методы.

 class View { public $templateFile; protected $properties = array(); public function __set($property, $value) { $this->properties[$property] = $value; } public function __get($property) { return @$this->properties[$property]; } public function __toString() { require_once 'smarty/libs/Smarty.class.php'; $smarty = new Smarty(); $smarty->template_dir = 'view'; $smarty->compile_dir = 'smarty/compile'; $smarty->config_dir = 'smarty/config'; $smarty->cache_dir = 'smarty/cache'; foreach ($this->properties as $property => $value) { $smarty->assign($property, $value); } return $smarty->fetch($this->templateFile); } } 

Скрытая выгода от этого подхода заключается в том, что вы можете вложить объекты вида один в другой:

 $index = new View(); $index->templateFile = 'index.tpl'; $topNav = new View(); $topNav->templateFile = 'topNav.tpl'; $index->topNav = $topNav; 

И в index.tpl , вложенность выглядит так:

 <html> <head></head> <body> {$topNav} Welcome to Foobar Corporation. </body> </html> 

Все вложенные объекты View преобразуются в строку (HTML, если быть точным) «на лету», как только вы echo $index;

Я думаю, что это плохо для дизайна кода. Если вы знаете и делаете хороший дизайн, вам не нужно будет использовать функции __set() и __get() в вашем коде. Кроме того, чтение кода очень важно, и если вы используете студию (например, студию Zend), то с помощью __set() и __get() вы не сможете увидеть свои свойства класса.

PHP позволяет динамически создавать переменные класса, что может вызвать проблемы. Вы можете использовать методы __set и __get, чтобы ограничить это поведение. Ниже приведен пример ниже …

 class Person { public $name; public function printProperties(){ print_r(get_object_vars($this)); } } $person = new Person(); $person->name = 'Jay'; //This is valid $person->printProperties(); $person->age = '26'; //This shouldn't work...but it does $person->printProperties(); 

для предотвращения выше вы можете это сделать ..

 public function __set($name, $value){ $classVar = get_object_vars($this); if(in_array($name, $classVar)){ $this->$name = $value; } } 

Надеюсь это поможет…

Они предназначены для «умных» вещей.

Например, вы можете использовать __set() и __get() для связи с базой данных. Тогда ваш код будет: $myObject->foo = "bar"; и это может обновить запись базы данных за кулисами. Конечно, вы должны быть очень осторожны с этим, или ваша производительность может пострадать, поэтому цитаты вокруг «умные» ðŸ™‚

Методы перегрузки особенно полезны при работе с объектами PHP, которые содержат данные, которые должны быть легко доступны. __get () вызывается при доступе к несуществующей собственности, __set () вызывается при попытке записать несуществующее свойство, а __call () вызывается, когда вызывается несуществующий метод.

Например, представьте себе, что класс управляет вашей конфигурацией:

 class Config { protected $_data = array(); public function __set($key, $val) { $this->_data[$key] = $val; } public function __get($key) { return $this->_data[$key]; } ...etc } 

Это упрощает чтение и запись объекта и дает вам возможность использовать пользовательские функции при чтении или записи на объект. Пример:

 $config = new Config(); $config->foo = 'bar'; echo $config->foo; // returns 'bar' 

Одна из оснований для их использования будет в плане системы реестра (я думаю, Zend Framework реализует это как класс реестра или конфигурации iirc), поэтому вы можете делать такие вещи, как

 $conf = new Config(); $conf->parent->child->grandchild = 'foo'; 

Каждое из этих свойств является автоматически созданным объектом Config, что-то похожее на:

 function __get($key) { return new Config($key); } 

Очевидно, что если $ conf-> parent уже существует, метод __get () не будет вызываться, поэтому использовать его для генерации новых переменных – хороший трюк.

Имейте в виду, что этот код, который я только что процитировал, не является функциональностью, я просто написал его быстро для примера.

Вероятно, это не самый чистый дизайн в мире, но у меня была ситуация, когда у меня было много кода, ссылающегося на переменную экземпляра в классе, то есть:

 $obj->value = 'blah'; echo $obj->value; 

но потом я хотел сделать что-то особенное, когда «значение» было установлено при определенных обстоятельствах, поэтому я переименовал переменную значений и реализовал __set () и __get () с необходимыми изменениями.

Остальная часть кода не знала разницы.