Analog Ioc container service

A service container is a powerful tool for managing and implementing class depends for dependency injection.

 A class to be able to extract container, you must first register to this container. Since the service is called, said the container vessel, then we need a service, you have to register, bind this service to the container, then the provision of services and binding service is something to container service provider (ServiceProvider).

Inversion of Control and the Dependency injection are different descriptions of the same thing, they describe different angles. Dependency injection is from the perspective of the application in the description, to create applications that rely on container and inject external resources it needs. And reversing control from the perspective of external resources in the description of the container, the container control applications, the reverse injection of the application to the application required by the container.

<?php

/**
 * Interface Log
 * Oriented programming interface
 */
interface Log
{
    public function write();
}

class FileLog implements Log
{
    public function write()
    {
        echo 'filelog write...' . PHP_EOL;
    }
}

class DataBaseLog implements Log
{
    public function write()
    {
        echo 'dblog write...' . PHP_EOL;
    }
}

/**
 * Class Request
 * Simulation of request classes
 */
class Request
{
    public function toArray()
    {
        return ['name' => 'value'];
    }
}

/**
 * User Interface class implementation-dependent Log
 */
class User
{
    private $log;
    private $extra;

    public function __construct(Log $log, $extra)
    {
        $this->log = $log;
        $this->extra = $extra;
    }

    /**
     * Written to simulate user login login log
     */
    public function login(Request $request)
    {
        echo 'json registration request reception parameters:' json_encode (. $ Request -> toArray ()). value is PHP_EOL ;
         echo 'User log Success ...'. value is PHP_EOL ;
         $ the this -> log -> Write ();
    }
}


/**
 * Class Ioc
 * Analog IoC container
 * Class from registration to instantiate, eventually we use, they are responsible for the container service
 */
class Ioc
{
    protected $bindings = [];
    protected $instances = [];
    protected static $ioc;

    protected function __construct()
    {
    }

    public static function getInstance()
    {
        if (is_null(self::$ioc)) {
            self::$ioc = new self();
        }
        return self::$ioc;
    }

    /**
     * Registered binding (binding itself, closures, interfaces)
     * Is service
     * @param $abstract
     * @param null $concrete
     */
    public function bind($abstract, $concrete = null, $params = [])
    {
        if (is_null($concrete)) {
            $concrete = $abstract;
        }

        if (!$concrete instanceof Closure) {
            $this->bindings[$abstract]['concrete'] = function (Ioc $ioc) use ($concrete, $params) {
                return $ioc->build($concrete, $params);
            };
        } else {
            $this->bindings[$abstract]['concrete'] = $concrete;
        }
    }

    /**
     * Returns the object
     * @param $abstract
     * @return mixed
     */
    public function make($abstract)
    {
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        if (isset($this->bindings[$abstract]['concrete'])) {
            $concrete = $this->bindings[$abstract]['concrete'];
            $instance = $concrete($this);
            $this->instances[$abstract] = $instance;
            return $instance;
        }

        throw new RuntimeException($abstract . ' is not bound yet');
    }

    /**
     * Create Object
     * @param $concrete
     * @return object
     * @throws ReflectionException
     */
    public function build($concrete, $params)
    {
        $reflectionClass = new ReflectionClass($concrete);
        $constructor = $reflectionClass->getConstructor();
        if (is_null($constructor)) {
            return $reflectionClass->newInstance();
        }
        $isInstantiable = $reflectionClass->isInstantiable();
        if (!$isInstantiable) {
            throw new ReflectionException("$concrete cant construct");
        }
        $parameters = $constructor->getParameters();
        $dependencies = $this->getDependencies($parameters, $params);
        return $reflectionClass->newInstanceArgs($dependencies);
    }

    /**
     * Get parameter dependence
     * @param array $parameters
     * @return array
     * @throws ReflectionException
     */
    public function getDependencies(array $parameters, $params = [])
    {
        $dependencies = [];
        /**
         * @Var ReflectionParameter $ parameter
         */
        foreach ($parameters as $parameter) {
            $dependency = $parameter->getClass();
            if (is_null($dependency)) {
                if ($parameter->isDefaultValueAvailable()) {
                    $dependency[] = $parameter->getDefaultValue();
                } else {
                    if (!isset($params['$' . $parameter->getName()])) {
                        throw new ReflectionException('The constructor of the ' . $parameter->getDeclaringClass()->getName() . ' class has no default value of $' . $parameter->getName());
                    }
                    $dependencies[] = $params['$' . $parameter->getName()];
                }
            } else {
                $dependencies[] = $this->make($dependency->name);
            }
        }
        return $dependencies;
    }
}

/**
 * Class Facade
 * Analog facade
 */
class Facade
{
    protected static function getFacadeClass()
    {
        return '';
    }

    public static function __callStatic($name, $arguments)
    {
        $instance = Ioc::getInstance()->make(static::getFacadeClass());
        return call_user_func_array([$instance, $name], $arguments);
    }
}

class UserFacade extends Facade
{
    protected static function getFacadeClass()
    {
        return 'User';
    }
}

// run
/*
 | Binding analog container
 * / 
$ IOC = Ioc :: getInstance ();
 $ IOC -> the bind (Request :: class ); // bind the class 
$ IOC -> the bind ( the Log :: class , filelog :: class ); // Bind interface
ioc- $ //> the bind (the Log class ::, :: DataBaseLog class); 
$ IOC -> the bind (the User :: class , null , [ '$ Extra' => 'additional parameters']); // bind class and supports additional parameter binding 
$ IOC -> the bind ( 'Test', function () { // bind closure 
    return 'Test'. value is PHP_EOL ;
});

/*
 | Login method in the analog routing User Access Controller
 */
$reflectionMethod = new ReflectionMethod(User::class, 'login');
$parameters = $reflectionMethod->getParameters();
$dependencies = $ioc->getDependencies($parameters);
$user = $ioc->make('test');
$user = $ioc->make(User::class);
// 普通调用
echo '普通调用:' . PHP_EOL;
call_user_func_array([$user, 'login'], $dependencies);
 // the Facade facade calls 
echo 'facade call:'. PHP_EOL ;
 call_user_func_array ([UserFacade :: class , 'the Login'], $ the Dependencies );

 

Guess you like

Origin www.cnblogs.com/cshaptx4869/p/11671003.html