| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 | <?php// +----------------------------------------------------------------------// | ThinkPHP [ WE CAN DO IT JUST THINK ]// +----------------------------------------------------------------------// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.// +----------------------------------------------------------------------// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )// +----------------------------------------------------------------------// | Author: liu21st <liu21st@gmail.com>// +----------------------------------------------------------------------namespace think;use ArrayAccess;use ArrayIterator;use Closure;use Countable;use InvalidArgumentException;use IteratorAggregate;use ReflectionClass;use ReflectionException;use ReflectionFunction;use ReflectionMethod;use think\exception\ClassNotFoundException;/** * @package think * @property Build          $build * @property Cache          $cache * @property Config         $config * @property Cookie         $cookie * @property Debug          $debug * @property Env            $env * @property Hook           $hook * @property Lang           $lang * @property Middleware     $middleware * @property Request        $request * @property Response       $response * @property Route          $route * @property Session        $session * @property Template       $template * @property Url            $url * @property Validate       $validate * @property View           $view * @property route\RuleName $rule_name * @property Log            $log */class Container implements ArrayAccess, IteratorAggregate, Countable{    /**     * 容器对象实例     * @var Container     */    protected static $instance;    /**     * 容器中的对象实例     * @var array     */    protected $instances = [];    /**     * 容器绑定标识     * @var array     */    protected $bind = [        'app'                   => App::class,        'build'                 => Build::class,        'cache'                 => Cache::class,        'config'                => Config::class,        'cookie'                => Cookie::class,        'debug'                 => Debug::class,        'env'                   => Env::class,        'hook'                  => Hook::class,        'lang'                  => Lang::class,        'log'                   => Log::class,        'middleware'            => Middleware::class,        'request'               => Request::class,        'response'              => Response::class,        'route'                 => Route::class,        'session'               => Session::class,        'template'              => Template::class,        'url'                   => Url::class,        'validate'              => Validate::class,        'view'                  => View::class,        'rule_name'             => route\RuleName::class,        // 接口依赖注入        'think\LoggerInterface' => Log::class,    ];    /**     * 容器标识别名     * @var array     */    protected $name = [];    /**     * 获取当前容器的实例(单例)     * @access public     * @return static     */    public static function getInstance()    {        if (is_null(static::$instance)) {            static::$instance = new static;        }        return static::$instance;    }    /**     * 设置当前容器的实例     * @access public     * @param  object        $instance     * @return void     */    public static function setInstance($instance)    {        static::$instance = $instance;    }    /**     * 获取容器中的对象实例     * @access public     * @param  string        $abstract       类名或者标识     * @param  array|true    $vars           变量     * @param  bool          $newInstance    是否每次创建新的实例     * @return object     */    public static function get($abstract, $vars = [], $newInstance = false)    {        return static::getInstance()->make($abstract, $vars, $newInstance);    }    /**     * 绑定一个类、闭包、实例、接口实现到容器     * @access public     * @param  string  $abstract    类标识、接口     * @param  mixed   $concrete    要绑定的类、闭包或者实例     * @return Container     */    public static function set($abstract, $concrete = null)    {        return static::getInstance()->bindTo($abstract, $concrete);    }    /**     * 移除容器中的对象实例     * @access public     * @param  string  $abstract    类标识、接口     * @return void     */    public static function remove($abstract)    {        return static::getInstance()->delete($abstract);    }    /**     * 清除容器中的对象实例     * @access public     * @return void     */    public static function clear()    {        return static::getInstance()->flush();    }    /**     * 绑定一个类、闭包、实例、接口实现到容器     * @access public     * @param  string|array  $abstract    类标识、接口     * @param  mixed         $concrete    要绑定的类、闭包或者实例     * @return $this     */    public function bindTo($abstract, $concrete = null)    {        if (is_array($abstract)) {            $this->bind = array_merge($this->bind, $abstract);        } elseif ($concrete instanceof Closure) {            $this->bind[$abstract] = $concrete;        } elseif (is_object($concrete)) {            if (isset($this->bind[$abstract])) {                $abstract = $this->bind[$abstract];            }            $this->instances[$abstract] = $concrete;        } else {            $this->bind[$abstract] = $concrete;        }        return $this;    }    /**     * 绑定一个类实例当容器     * @access public     * @param  string           $abstract    类名或者标识     * @param  object|\Closure  $instance    类的实例     * @return $this     */    public function instance($abstract, $instance)    {        if ($instance instanceof \Closure) {            $this->bind[$abstract] = $instance;        } else {            if (isset($this->bind[$abstract])) {                $abstract = $this->bind[$abstract];            }            $this->instances[$abstract] = $instance;        }        return $this;    }    /**     * 判断容器中是否存在类及标识     * @access public     * @param  string    $abstract    类名或者标识     * @return bool     */    public function bound($abstract)    {        return isset($this->bind[$abstract]) || isset($this->instances[$abstract]);    }    /**     * 判断容器中是否存在对象实例     * @access public     * @param  string    $abstract    类名或者标识     * @return bool     */    public function exists($abstract)    {        if (isset($this->bind[$abstract])) {            $abstract = $this->bind[$abstract];        }        return isset($this->instances[$abstract]);    }    /**     * 判断容器中是否存在类及标识     * @access public     * @param  string    $name    类名或者标识     * @return bool     */    public function has($name)    {        return $this->bound($name);    }    /**     * 创建类的实例     * @access public     * @param  string        $abstract       类名或者标识     * @param  array|true    $vars           变量     * @param  bool          $newInstance    是否每次创建新的实例     * @return object     */    public function make($abstract, $vars = [], $newInstance = false)    {        if (true === $vars) {            // 总是创建新的实例化对象            $newInstance = true;            $vars        = [];        }        $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;        if (isset($this->instances[$abstract]) && !$newInstance) {            return $this->instances[$abstract];        }        if (isset($this->bind[$abstract])) {            $concrete = $this->bind[$abstract];            if ($concrete instanceof Closure) {                $object = $this->invokeFunction($concrete, $vars);            } else {                $this->name[$abstract] = $concrete;                return $this->make($concrete, $vars, $newInstance);            }        } else {            $object = $this->invokeClass($abstract, $vars);        }        if (!$newInstance) {            $this->instances[$abstract] = $object;        }        return $object;    }    /**     * 删除容器中的对象实例     * @access public     * @param  string|array    $abstract    类名或者标识     * @return void     */    public function delete($abstract)    {        foreach ((array) $abstract as $name) {            $name = isset($this->name[$name]) ? $this->name[$name] : $name;            if (isset($this->instances[$name])) {                unset($this->instances[$name]);            }        }    }    /**     * 获取容器中的对象实例     * @access public     * @return array     */    public function all()    {        return $this->instances;    }    /**     * 清除容器中的对象实例     * @access public     * @return void     */    public function flush()    {        $this->instances = [];        $this->bind      = [];        $this->name      = [];    }    /**     * 执行函数或者闭包方法 支持参数调用     * @access public     * @param  mixed  $function 函数或者闭包     * @param  array  $vars     参数     * @return mixed     */    public function invokeFunction($function, $vars = [])    {        try {            $reflect = new ReflectionFunction($function);            $args = $this->bindParams($reflect, $vars);            return call_user_func_array($function, $args);        } catch (ReflectionException $e) {            throw new Exception('function not exists: ' . $function . '()');        }    }    /**     * 调用反射执行类的方法 支持参数绑定     * @access public     * @param  mixed   $method 方法     * @param  array   $vars   参数     * @return mixed     */    public function invokeMethod($method, $vars = [])    {        try {            if (is_array($method)) {                $class   = is_object($method[0]) ? $method[0] : $this->invokeClass($method[0]);                $reflect = new ReflectionMethod($class, $method[1]);            } else {                // 静态方法                $reflect = new ReflectionMethod($method);            }            $args = $this->bindParams($reflect, $vars);            return $reflect->invokeArgs(isset($class) ? $class : null, $args);        } catch (ReflectionException $e) {            if (is_array($method) && is_object($method[0])) {                $method[0] = get_class($method[0]);            }            throw new Exception('method not exists: ' . (is_array($method) ? $method[0] . '::' . $method[1] : $method) . '()');        }    }    /**     * 调用反射执行类的方法 支持参数绑定     * @access public     * @param  object  $instance 对象实例     * @param  mixed   $reflect 反射类     * @param  array   $vars   参数     * @return mixed     */    public function invokeReflectMethod($instance, $reflect, $vars = [])    {        $args = $this->bindParams($reflect, $vars);        return $reflect->invokeArgs($instance, $args);    }    /**     * 调用反射执行callable 支持参数绑定     * @access public     * @param  mixed $callable     * @param  array $vars   参数     * @return mixed     */    public function invoke($callable, $vars = [])    {        if ($callable instanceof Closure) {            return $this->invokeFunction($callable, $vars);        }        return $this->invokeMethod($callable, $vars);    }    /**     * 调用反射执行类的实例化 支持依赖注入     * @access public     * @param  string    $class 类名     * @param  array     $vars  参数     * @return mixed     */    public function invokeClass($class, $vars = [])    {        try {            $reflect = new ReflectionClass($class);            if ($reflect->hasMethod('__make')) {                $method = new ReflectionMethod($class, '__make');                if ($method->isPublic() && $method->isStatic()) {                    $args = $this->bindParams($method, $vars);                    return $method->invokeArgs(null, $args);                }            }            $constructor = $reflect->getConstructor();            $args = $constructor ? $this->bindParams($constructor, $vars) : [];            return $reflect->newInstanceArgs($args);        } catch (ReflectionException $e) {            throw new ClassNotFoundException('class not exists: ' . $class, $class);        }    }    /**     * 绑定参数     * @access protected     * @param  \ReflectionMethod|\ReflectionFunction $reflect 反射类     * @param  array                                 $vars    参数     * @return array     */    protected function bindParams($reflect, $vars = [])    {        if ($reflect->getNumberOfParameters() == 0) {            return [];        }        // 判断数组类型 数字数组时按顺序绑定参数        reset($vars);        $type   = key($vars) === 0 ? 1 : 0;        $params = $reflect->getParameters();        foreach ($params as $param) {            $name      = $param->getName();            $lowerName = Loader::parseName($name);            // $classType = $param->getType();            // $class      = null !== $classType && !$classType->isBuiltin() ? $classType->getName() : null;            // if ($class) {            //     $args[] = $this->getObjectParam($classType->getName(), $vars);            $class     = $param->getClass();            if ($class) {                $args[] = $this->getObjectParam($class->getName(), $vars);            } elseif (1 == $type && !empty($vars)) {                $args[] = array_shift($vars);            } elseif (0 == $type && isset($vars[$name])) {                $args[] = $vars[$name];            } elseif (0 == $type && isset($vars[$lowerName])) {                $args[] = $vars[$lowerName];            } elseif ($param->isDefaultValueAvailable()) {                $args[] = $param->getDefaultValue();            } else {                throw new InvalidArgumentException('method param miss:' . $name);            }        }        return $args;    }    /**     * 获取对象类型的参数值     * @access protected     * @param  string   $className  类名     * @param  array    $vars       参数     * @return mixed     */    protected function getObjectParam($className, &$vars)    {        $array = $vars;        $value = array_shift($array);        if ($value instanceof $className) {            $result = $value;            array_shift($vars);        } else {            $result = $this->make($className);        }        return $result;    }    public function __set($name, $value)    {        $this->bindTo($name, $value);    }    public function __get($name)    {        return $this->make($name);    }    public function __isset($name)    {        return $this->bound($name);    }    public function __unset($name)    {        $this->delete($name);    }    public function offsetExists($key)    {        return $this->__isset($key);    }    public function offsetGet($key)    {        return $this->__get($key);    }    public function offsetSet($key, $value)    {        $this->__set($key, $value);    }    public function offsetUnset($key)    {        $this->__unset($key);    }    //Countable    public function count()    {        return count($this->instances);    }    //IteratorAggregate    public function getIterator()    {        return new ArrayIterator($this->instances);    }    public function __debugInfo()    {        $data = get_object_vars($this);        unset($data['instances'], $data['instance']);        return $data;    }}
 |