аналогичный вопрос обсуждает __construct, но я оставил его в своем заголовке для людей, которые ищут этот.
Очевидно, __get и __set принимают параметр, который является получаемой или устанавливаемой переменной. Однако вы должны знать имя переменной (например, знать, что возраст человека равен $ age, а не $ myAge). Так что я не вижу смысла, если вы ДОЛЖНЫ знать имя переменной, особенно если вы работаете с незнакомым кодом (например, с библиотекой).
Я нашел несколько страниц, объясняющих __get(), __set() и __call(), но я до сих пор не понимаю, почему и когда они полезны.






Эта страница, наверное, пригодится. (Обратите внимание, что то, что вы говорите, неверно - __set() принимает в качестве параметра как имя переменной, так и значение. __get() просто принимает имя переменной).
__get() и __set() полезны в библиотечных функциях, где вы хотите предоставить общий доступ к переменным. Например, в классе ActiveRecord вы можете захотеть, чтобы люди имели доступ к полям базы данных как к свойствам объекта. Например, в PHP-фреймворке Kohana вы можете использовать:
$user = ORM::factory('user', 1);
$email = $user->email_address;
Это достигается с помощью __get() и __set().
Нечто подобное можно сделать при использовании __call(), т.е. вы можете определить, когда кто-то вызывает getProperty () и setProperty (), и обработать его соответствующим образом.
Они делают «умные» вещи.
Например, вы можете использовать __set() и __get() для связи с базой данных. Тогда ваш код будет: $myObject->foo = "bar";, и это может незаметно обновить запись в базе данных. Конечно, вы должны быть очень осторожны с этим, иначе ваша производительность может пострадать, поэтому цитаты вокруг слова «умный» :)
Методы Перегрузка особенно полезны при работе с объектами PHP, которые содержат данные, которые должны быть легко доступны. __получить() вызывается при доступе к несуществующему свойству, __набор() вызывается при попытке записать несуществующее свойство, а __вызов() вызывается при вызове несуществующего метода.
Например, представьте, что у вас есть класс, управляющий вашей конфигурацией:
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'
__get (), __set () и __call () - это то, что PHP называет «магическими методами», что является прозвищем. Я думаю, что это немного глупо - я думаю, что «крючок» немного более уместен. Во всяком случае, я отвлекся ...
Их цель - предоставить варианты выполнения, когда осуществляется доступ к элементам данных (свойствам или методам), которые не определены для объекта, которые могут использоваться для всех видов «умных» мыслей, таких как скрытие переменных, пересылка сообщений и т. д.
Однако есть цена - вызов, который их вызывает, примерно в 10 раз медленнее, чем вызов определенных камер данных.
Есть ли у вас ссылки на то, что он работает медленнее? Не то чтобы я тебе не верю (потому что верю), но я надеюсь, что это не так.
Переопределение __get и __set может быть особенно полезно в базовых классах. Например, если вы не хотите, чтобы ваша конфигурация была случайно перезаписана, но все же хотите получить из нее данные:
class Example
{
private $config = array('password' => 'pAsSwOrD');
public function __get($name)
{
return $this->config[$name];
}
}
Одна из веских причин для их использования - это система реестра (я думаю, что 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 () с необходимыми мне изменениями.
Остальная часть кода не знала разницы.
Еще одно полезное применение магических методов, особенно __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);
}
}
Скрытым преимуществом этого подхода является то, что вы можете вкладывать объекты View один в другой:
$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 studio), с __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;
}
}
Надеюсь это поможет...
Мне не нравится такое использование этих методов. В лучшем случае это синтаксический сахар, который просто замедляет работу вашего приложения. Я бы предпочел увидеть класс, реализующий интерфейс SPL ArrayAccess, или просто общий набор методов get / set. Это должно быть «использовать по необходимости, а не когда удобно».