PHP 如何优雅地实现类中变量的懒初始化( Initialized when visited)

2016-09-17 09:13:06 +08:00
 dangyuluo

有这么个需求,就是应用程序依赖两个 composer 类库 A 和 B , AB 都挺重量级的因此加载时间会稍长。

目前有个数据库操作类 DB (其实例名称为$db ),该类会在特定条件下调用 A 或者 B ,因此我想将 A, B 生成的对象 a, b 赋予数据库类,如$db->a, $db->b。 但是,并不是所有场合下 A 或 B 内的方法都会被调用,因此在 DB 类的构造函数内预先将 a, b 初始化好的话会再大量请求中浪费掉二者的初始化时间(尤其再 AB 还是重量级类库的情况下)。

我原先的做法是以类中方法返回对象的途径实现的懒加载,如下

class DB{
	public $a, $b;
    
	private function get_a(){
    	return isset($this->a)?$this->a:new A($init_params);
    } 
    
    //使用 a 的时候便可以如下:
    public function use_a(){
    $this->get_a()->methods_of_a();
    }
}

然后我又改成了使用 PHP 魔术方法__set()来进行,但是有点臃肿。

因此请问大家有什么好的建议么?

2799 次点击
所在节点    PHP
5 条回复
gdtv
2016-09-17 09:19:58 +08:00
我遇到过类似的需求,也是用你这样的方法解决
ljbha007
2016-09-17 10:17:24 +08:00
__get 里面写也很好啊
gouchaoer
2016-09-17 13:44:42 +08:00
典型的依赖注入单例需求嘛,可以参考 yii2 的 component 机制
AbrahamGreyson
2016-09-17 21:15:55 +08:00
策略模式。
klom303
2016-09-18 16:34:19 +08:00
第一次回复,这种懒加载可以用闭包哦

class DB
{
private $binds = [];
private $instances = [];

public function __construct()
{
$this->bind('a', function ($config) {
return new A($config);
});
$this->bind('b', function ($config) {
return new B($config);
});
}

private function bind($key, Closure $closure)
{
if (!isset($this->binds[$key])) {
$this->binds[$key] = $closure;
}
}

public function make($key, array $params)
{
if (isset($this->instances[$key])) {
return $this->instances[$key];
}
if (!isset($this->binds[$key])) {
return false;
}
$this->instances[$key] = call_user_func_array($this->binds[$key], $params);
return $this->instances[$key];
}
}

class A
{
private $config;

public function __construct($config)
{
$this->config = $config;
}

public function foo()
{
echo "Class A:\n";
var_dump($this->config);
}
}

class B
{
private $config;

public function __construct($config)
{
$this->config = $config;
}

public function foo()
{
echo "Class B:\n";
var_dump($this->config);
}
}

$db = new DB();
$a = $db->make('a', ['config for a']);
$a->foo();
$b = $db->make('b', ['config for b']);
$b->foo();

这确实是单例+依赖注入的问题
DB 类一般是要做单例的,这里只是写个例子就直接 new 了,不对的话请指教

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/306710

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX