При необходимости создать объект, определенный как свойство в классе 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. Это немного мощнее.

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