V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dangyuluo
V2EX  ›  PHP

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

  •  
  •   dangyuluo · 2016-09-17 09:13:06 +08:00 · 2793 次点击
    这是一个创建于 2778 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有这么个需求,就是应用程序依赖两个 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()来进行,但是有点臃肿。

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

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

    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 了,不对的话请指教
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4875 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 09:50 · PVG 17:50 · LAX 02:50 · JFK 05:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.