Аналогичный вопрос обсуждается __construct
, но я оставил его в своем названии для поиска людей, которые его находят.
По-видимому, __get и __set принимают параметр, который получает или задает переменную. Однако вы должны знать имя переменной (например, знаете, что возраст человека – это $ age вместо $ myAge). Поэтому я не вижу смысла, если вам нужно знать имя переменной, особенно если вы работаете с кодом, с которым вы не знакомы (например, с библиотекой).
Я нашел несколько страниц, которые объясняют __get()
, __set()
и __call()
, но я до сих пор не понимаю, почему и когда они полезны.
Эта страница , вероятно, будет полезна. (Обратите внимание, что то, что вы говорите, неверно – __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 () с необходимыми изменениями.
Остальная часть кода не знала разницы.