При необходимости создать объект, определенный как свойство в классе PHP (отложенная загрузка)
Для простоты предположим, что у меня есть 2 класса, User и UserStatus, используемые в веб-приложении.
<?php
// library code:
class UserStatus {
protected $_status = NULL;
private function fetchDataFromDB() {
// regular DB stuff
$this->_status = ...
// result will be something like 'online', 'away', etc.
}
public function getIcon() {
global $icon_array;
if (is_null($this->_status)) {
$this->fetchDataFromDB()
}
return $icon_array[$this->_status];
}
}
class User {
protected $user_id;
public $user_name;
protected $status;
public function __construct() {}
public static function getAll() {
// some DB stuff
return $users;
}
}
// and now, in index.php:
$users = User::getAll();
// echoes the icon to use to reflect the current user status
foreach ($users as $user) {
echo <img src="$user->status->getIcon()"/>;
}
?>
В большинстве HTTP-запросов объект состояния не будет использоваться, поэтому я ищу способ только создавать его экземпляры по мере необходимости (называть это отложенной загрузкой). Как я должен перехватить status->method()
вызвать и создать этот объект на лету?
Важное замечание, что мне нужно $user_id
доступны в классе UserStatus, в противном случае fetchDataFromDB()
Метод не будет знать, какому пользователю он должен получить данные. Как это должно быть сделано?
Я посмотрел на некоторые интересные вещи по этому вопросу, такие как " Инъекция зависимости" Фабьена Потенциера ? и Pimple - контейнер для внедрения зависимостей PHP 5.3, а также некоторые статьи о Proxy Pattern, но для их реализации, похоже, мне приходится много путаться с текущим кодом. Есть ли более простой способ?
2 ответа
Может быть, я что-то упустил, но кажется, что самым простым решением в этом случае было бы, чтобы ваш получатель для Status просто создал объект, если он не существует...
public function getStatus()
{
if(!isset($this->status))
{
// or however you creat this object..
$this->status = new UserStatus($this->user_id);
}
return $this->status;
}
public function __get($property)
{
$method = 'get'.ucfirst($property); // getStatus
if(method_exists($this, $method))
{
return $this->$method();
}
}
Используя __get
магический метод в любое время вы делаете $user->status
это позвонит $user->getStatus()
, Конечно, вы всегда можете просто получить к нему доступ, как: $user->getStatus()->getIcon()
также.
Однако вы решите настроить доступ к своим свойствам, и я бы порекомендовал сделать это согласованно для всей вашей модели.
Вы можете поместить класс статуса в другой файл, а затем использовать механизм автозагрузки php:
http://php.net/manual/de/language.oop5.autoload.php
не загружать этот файл, пока вы не получите к нему доступ.
Ходят слухи, что автоматическая загрузка (или фактически любая условная загрузка) является проблематичной для кэшей байтового кода и оптимизаторов, хотя, к сожалению, я не знаю слишком много о влиянии.
PS: в данном руководстве не говорится об этом подробно: вы также можете использовать spl_autoload_register() вместо того, чтобы просто определять магическую функцию __autoload. Это немного мощнее.