这货是从 Martin 大神的《企业应用架构模式》中学到的,辅助 PHP 动态语言的特性,可以比 Java 轻松很多的实现延迟加载(LazyLoad)。基本原理是通过一个虚代理(Virtual Proxy)做占位符,一旦访问代理对象的某成员(方法或属性),加载就被触发。
不过我实现的这个版本有局限性:
- 只适用于对象,无法代理数组等基本数据类型(需要用 ArrayObject 一类的内置对象封装)
- 被代理之后,一些带有操作符重载性质的接口实现就失效了,例如 ArrayAccess 的索引器、Itreator 的迭代器,如果是用该代理来处理集合类型的延迟加载,还需要继承一个子类做特殊处理,以便外部用 foreach 迭代
详见我的博客:http://tonyseek.tumblr.com/post/6166066775/virtual-proxy-lazy-load
- // 测试
- $v = new VirtualProxy(function(){
- echo 'Now, Loading', "n";
- $a = new ArrayObject(range(1,100));
- $a->abc = 'a';
- // 实际使用中,这里调用的是 DataMapper 的 findXXX 方法
- // 返回的是领域对象集合
- return $a;
- });
- // 代理对象直接当作原对象访问
- // 而此时构造方法传入的 callback 函数才被调用
- // 从而实现加载对象操作的延迟
- echo $v->abc . $v->offsetGet(50);
-
复制代码
- /**
- * 虚代理,只有在被访问成员时才调用闭包函数生成目标对象。
- *
- * @author tonyseek
- *
- */
- class VirtualProxy
- {
- private $holder = null;
- private $loader = null;
-
- /**
- * 虚代理,只有在被访问成员时才调用闭包函数生成目标对象。
- *
- * @param Closure $loader 生成被代理对象的闭包函数
- */
- public function __construct(Closure $loader)
- {
- $this->loader = $loader;
- }
-
- /**
- * 代理成员方法的调用
- *
- * @param string $method
- * @param array $arguments
- * @throws BadMethodCallException
- * @return mixed
- */
- public function __call($method, array $arguments = null)
- {
- $this->check();
-
- if (!method_exists($this->holder, $method)) {
- throw new BadMethodCallException();
- }
-
- return call_user_func_array(
- array(&$this->holder, $method),
- $arguments);
- }
-
- /**
- * 代理成员属性的读取
- *
- * @param string $property
- * @throws ErrorException
- * @return mixed
- */
- public function __get($property)
- {
- $this->check();
-
- if (!isset($this->holder->$property)) {
- throw new ErrorException();
- }
-
- return $this->holder->$property;
- }
-
- /**
- * 代理成员属性的赋值
- *
- * @param string $property
- * @param mixed $value
- */
- public function __set($property, $value)
- {
- $this->check();
-
- $this->holder->$property = $value;
- }
-
- /**
- * 检查是否已经存在被代理对象,不存在则生成。
- */
- private function check()
- {
- if (null == $this->holder) {
- $loader = $this->loader;
- $this->holder = $loader();
- }
- }
- }
复制代码
|