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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
11
0
7 672
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Ответ принят как подходящий

Эта страница, наверное, пригодится. (Обратите внимание, что то, что вы говорите, неверно - __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'

Мне не нравится такое использование этих методов. В лучшем случае это синтаксический сахар, который просто замедляет работу вашего приложения. Я бы предпочел увидеть класс, реализующий интерфейс SPL ArrayAccess, или просто общий набор методов get / set. Это должно быть «использовать по необходимости, а не когда удобно».

Peter Bailey 30.10.2008 19:05

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

Их цель - предоставить варианты выполнения, когда осуществляется доступ к элементам данных (свойствам или методам), которые не определены для объекта, которые могут использоваться для всех видов «умных» мыслей, таких как скрытие переменных, пересылка сообщений и т. д.

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

Есть ли у вас ссылки на то, что он работает медленнее? Не то чтобы я тебе не верю (потому что верю), но я надеюсь, что это не так.

Darryl Hein 01.11.2010 08:48

Переопределение __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;
    }
}

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

Другие вопросы по теме