瞭解PHP容器(Container)的實現

看 Laravel 源代碼瞭解 Containerphp

Dependency Injection Containers 的基本功能:數組

  • Container 管理對象實例化到配置的過程
  • 對象自己不知道本身是由 Container 管理的,對 Container 一無所知。

這就是爲何 Container 可以管理任何 PHP 對象。 對象使用 DI 來管理依賴關係很是好,但不是必須的。閉包

i

<?php
function info($msg){
    echo $msg;
}

class LogToFile {
    public function execute($message) {
        info('log the message to a 美羊羊 :'.$message);
    }
}

class UseLogger {
    protected $logger;

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

    public function show() {
        $user = '小灰灰';
        $this->logger->execute($user);
    }
}

$useLogger = new UseLogger(new LogToFile());

$useLogger->show();

ii

A

<?php
 
function info($msg){
    echo $msg;
}


class LogToFile {
    public function execute($message) {
        info('log the message to a 美羊羊  :'.$message);
    }
}

class LogToDD {
    public function execute($message) {
        info('log the message to 喜羊羊 :'.$message);
    }
}

 
class UseLogger {
    protected $logger;

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

    public function show() {
        $user = '小灰灰';
        $this->logger->execute($user);
    }
}
$useLogger = new UseLogger(new LogToFile());
 
$useLogger->show();

B

<?php
 
function info($msg){
    echo $msg;
}

class LogToFile {
    public function execute($message) {
        info('log the message to a 美羊羊  :'.$message);
    }
}

class LogToDD {
    public function execute($message) {
        info('log the message to 喜羊羊 :'.$message);
    }
}

 
class UseLogger {
    protected $logger;

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

    public function show() {
        $user = '小灰灰';
        $this->logger->execute($user);
    }
}
$useLogger = new UseLogger(new LogToDD());
 
$useLogger->show();

iii

<?php

function info($msg){
    echo $msg;
}

interface Logger {
    public function execute($message);
}

class LogToFile implements Logger {
    public function execute($message) {
        info('log the message to a 美羊羊 :'.$message);
    }
}

class LogToDD implements Logger {
    public function execute($message) {
        info('log the message to 喜羊羊 :'.$message);
    }
}
 
class UseLogger {
    protected $logger;

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

    public function show() {
        $user = '小灰灰';
        $this->logger->execute($user);
    }
}

$useLogger = new UseLogger(new LogToFile());
 
$useLogger->show();

echo '<br>';

$useLogger = new UseLogger(new LogToDD());
 
$useLogger->show();

終極版

<?php
 
function info($msg){
    echo $msg;
}

interface Logger {
    public function execute($message);
}

class LogToFile implements Logger {
    public function execute($message) {
        info('log the message to a 美羊羊 :'.$message);
    }
}

class LogToDD implements Logger {
    public function execute($message) {
        info('log the message to 喜羊羊 :'.$message);
    }
}
 
class UseLogger {
    protected $logger;

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

    public function show() {
        $user = '小灰灰';
        $this->logger->execute($user);
 
    }
}

class SimpleContainer {

    // 用於存儲全部綁定 key-value
    protected static $container = [];

    public static function bind($name, Callable $resolver) {
        static::$container[$name] = $resolver;
    }

    public static function make($name) {
        if(isset(static::$container[$name])){
            $resolver = static::$container[$name] ;
            return $resolver();
        }
        throw new Exception("Binding does not exist in container");
    }
}

SimpleContainer::bind(Logger::class, function () {
    return new LogToDD();
});

$useLogger3 = new UseLogger(SimpleContainer::make(Logger::class));


$useLogger3->show();

示例

<?php

interface SuperModuleInterface{
    public function activate(array $target);
}

class Superman
{
    protected $module;

    /**
     * Superman constructor.
     * @param SuperModuleInterface $module
     * 經過構造器 注入依賴
     */
    public function __construct(SuperModuleInterface $module)
    {
        $this->module = $module;
    }

    public function show(array $target){

        $this->module->activate($target);
    }
}

class PowerA implements SuperModuleInterface
{
    public function activate(array $target)
    {
        echo '<pre>'. __METHOD__;
        print_r(func_get_args());
    }
}

class PowerB implements SuperModuleInterface
{
    public function activate(array $target)
    {
        echo '<pre>'. __METHOD__;
        print_r(func_get_args());
    }
}



class Container
{
    protected $binds;

    protected $instances;

    /**
     * @param $abstract
     * @param $concrete
     * 把代詞 綁定到容器裏,爲後續make
     */
    public function bind($abstract, $concrete)
    {
        if ($concrete instanceof Closure) {
            $this->binds[$abstract] = $concrete;
        } else {
            $this->instances[$abstract] = $concrete;
        }
    }

    /**
     * @param $abstract
     * @param array $parameters
     * @return mixed
     * 建立對象
     */
    public function make($abstract, $parameters = [])
    {
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }
        // 把容器對象$this,放到參數數組第一個元素。爲call_user_func_array使用
        array_unshift($parameters, $this);
        
        // 這裏$this->binds[$abstract] 綁定的閉包函數, 執行函數參數是$parameters
        return call_user_func_array($this->binds[$abstract], $parameters);
    }
}


// 建立一個容器(後面稱做超級工廠)
$container = new Container;


// 向該 超級工廠添加超能力模組的生產腳本
$container->bind('powerA', function($container) {
    return new PowerA;
});

// 同上
$container->bind('powerB', function($container) {
    return new PowerB;
});


// 向該 超級工廠添加超人的生產腳本
$container->bind('superman', function($container, $moduleName) {
    return new Superman($container->make($moduleName));
});



echo "<pre>";

// 開始啓動生產
$superman_1 = $container->make('superman', ['powerA']);
$superman_1->show(['a' => 1]);

$superman_2 = $container->make('superman', ['powerB']);
$superman_2->show(['b' => 1]);
相關文章
相關標籤/搜索