Когда нужно / нужно использовать __construct (), __get (), __set () и __call () в PHP? - PullRequest
10 голосов
/ 30 октября 2008

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

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

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

Ответы [ 10 ]

6 голосов
/ 30 октября 2008

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

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

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

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

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

5 голосов
/ 30 октября 2008

__ get (), __set () и __call () - это то, что PHP называет «магическими методами», это прозвище, я думаю, что это немного глупо, я думаю, что «ловушка» немного более подходящая. Во всяком случае, я отвлекся ...

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

Однако существует определенная цена - вызов, который их вызывает, примерно в 10 раз медленнее, чем вызов определенных камер данных.

3 голосов
/ 30 октября 2008

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

class Example
{
    private $config = array('password' => 'pAsSwOrD');
    public function __get($name)
    {
        return $this->config[$name];
    }
}
2 голосов
/ 30 октября 2008

Другое полезное применение магических методов, особенно __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;

1 голос
/ 16 февраля 2013

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

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

1 голос
/ 04 ноября 2009

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

0 голосов
/ 30 октября 2008

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

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

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

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

0 голосов
/ 30 октября 2008

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

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

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

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

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

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

0 голосов
/ 30 октября 2008

Перегрузка методы особенно полезны при работе с объектами 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'
0 голосов
/ 30 октября 2008

Они для того, чтобы делать "умные" вещи.

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

...