为简单起见,假设我有2个类,User和UserStatus,用于Web应用程序。
<?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()
调用并即时创建该对象?
一个重要的注意事项是我需要在UserStatus类中提供$user_id
,否则fetchDataFromDB()
方法将不知道应该从哪个用户获取数据。该怎么做?
我在Fabien Potencier的What is Dependency Injection?和Pimple - a PHP 5.3 dependency injection container这个问题上看过一些有趣的内容,还有一些关于代理模式的文章,但要实现它们看起来像我必须使用当前代码混乱很多。有更简单的方法吗?
答案 0 :(得分:3)
也许我错过了一些东西,但似乎这个实例中最简单的解决方案是让你的状态的getter只是创建对象,如果它不存在...
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()
。
但是,您决定设置访问您的属性,我建议您在整个模型中以一致的方式进行操作。
答案 1 :(得分:1)
您可以将状态类放在不同的文件中,然后利用php的自动加载机制:
http://php.net/manual/de/language.oop5.autoload.php
在您访问该文件之前不加载该文件。
有传言称自动加载(或实际上只是任何类型的条件加载)对于字节码缓存和优化器来说很麻烦,但不幸的是我对这种影响知之甚少。
P.S。:手册并没有说明这一点:你也可以使用spl_autoload_register()而不是仅仅定义魔法__autoload函数。这稍微强一点。