ThinkPHP容器之容器是如何返回实例的

在之前的文章中我们简单的梳理了一下容器类,接下来就是对其中一个细节进行深度分析。

Container实例调用make方法

本文没有太多文字解析,都在代码注释中说明了执行过程。

代码Static::getInstance()返回了Container的实例后,就会去调用本类的make方法,接下来就是对make方法进行详解了。

ThinkPHP容器之容器是如何返回实例的在开始阅读make方法里边的源码之前,我们需要先对几个属性进行简单的梳理一下。

这四个属性一定要有点印象,并且一定要区别instance和instances。

这俩个属性一个是单例模式返回当前类的实例,一个是容器中的所有的实例。

ThinkPHP容器之容器是如何返回实例的第一次执行结果

<span style="display: block; background: url(https://my-wechat.mdnice.com/point.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span>   <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br>     * 创建类的实例<br>     * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@access</span> public<br>     * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@param</span>  string        $abstract       类名或者标识<br>     * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@param</span>  array|true    $vars           变量<br>     * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@param</span>  bool          $newInstance    是否每次创建新的实例<br>     * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@return</span> object<br>     */</span><br>    <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">public</span> <span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">function</span> <span class="hljs-title" style="color: #61aeee; line-height: 26px;">make</span><span class="hljs-params" style="line-height: 26px;">($abstract, $vars = [], $newInstance = false)</span><br>    </span>{<br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 判断$vars这个变量是否为true</span><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">true</span> === $vars) {<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 总是创建新的实例化对象</span><br>            $newInstance = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">true</span>;<br>            $vars        = [];<br>        }<br><br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// app  这里就是在容器别名里获取传递过来的app    如果没有则就是app</span><br>        $abstract = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">isset</span>(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;name[$abstract]) ? <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;name[$abstract] : $abstract;<br>        <br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 从容器实例中获取  如果存在则直接返回对应的实例  也就是使用注册树模式</span><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">isset</span>(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;instances[$abstract]) &amp;&amp; !$newInstance) {<br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;instances[$abstract];<br>        }<br><br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// thinkApp 从容器标识中获取</span><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">isset</span>(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;bind[$abstract])) {<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 将thinkApp 复制给$concrete变量</span><br>            $concrete = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;bind[$abstract];<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 用于代表匿名函数的类  判断是不是闭包</span><br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> ($concrete <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">instanceof</span> Closure) {<br>                $object = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;invokeFunction($concrete, $vars);<br>            } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">else</span> {<br>                <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// $this-&gt;name['app'] = thinkApp</span><br>                <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;name[$abstract] = $concrete;<br>                <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 在执行一次本类的make方法,也就是本方法</span><br>                <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;make($concrete, $vars, $newInstance);<br>            }<br>        } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">else</span> {<br>            $object = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;invokeClass($abstract, $vars);<br>        }<br><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (!$newInstance) {<br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;instances[$abstract] = $object;<br>        }<br><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> $object;<br>    }<br>

这是第二次执行流程

<span style="display: block; background: url(https://my-wechat.mdnice.com/point.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span>    <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">public</span> <span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">function</span> <span class="hljs-title" style="color: #61aeee; line-height: 26px;">make</span><span class="hljs-params" style="line-height: 26px;">($abstract, $vars = [], $newInstance = false)</span><br>    </span>{<br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 判断$vars这个变量是否为true</span><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">true</span> === $vars) {<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 总是创建新的实例化对象</span><br>            $newInstance = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">true</span>;<br>            $vars        = [];<br>        }<br><br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// app  这里就是在容器别名里获取传递过来的app    如果没有则就是app</span><br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 第二次执行时 $abstract = thinkApp</span><br>        $abstract = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">isset</span>(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;name[$abstract]) ? <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;name[$abstract] : $abstract;<br><br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 从容器实例中获取  如果存在则直接返回对应的实例  也就是使用注册树模式</span><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">isset</span>(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;instances[$abstract]) &amp;&amp; !$newInstance) {<br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;instances[$abstract];<br>        }<br><br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// thinkApp 从容器标识中获取</span><br>        <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 第二次执行$this-&gt;bind['thinkApp']不存在走else</span><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">isset</span>(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;bind[$abstract])) {<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 将thinkApp 复制给$concrete变量</span><br>            $concrete = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;bind[$abstract];<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 用于代表匿名函数的类  判断是不是闭包</span><br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> ($concrete <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">instanceof</span> Closure) {<br>                $object = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;invokeFunction($concrete, $vars);<br>            } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">else</span> {<br>                <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// $this-&gt;name['app'] = thinkApp</span><br>                <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;name[$abstract] = $concrete;<br>                <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 在执行一次本类的make方法,也就是本方法</span><br>                <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// thinkApp</span><br>                <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;make($concrete, $vars, $newInstance);<br>            }<br>        } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">else</span> {<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// thinkApp</span><br>            $object = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;invokeClass($abstract, $vars);<br>        }<br><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (!$newInstance) {<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 把创建的容器存起来</span><br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//$this-&gt;instances['thinkApp'] = $object;</span><br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;instances[$abstract] = $object;<br>        }<br><br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> $object;<br>    }<br>
<span style="display: block; background: url(https://my-wechat.mdnice.com/point.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">public</span> <span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">function</span> <span class="hljs-title" style="color: #61aeee; line-height: 26px;">invokeClass</span><span class="hljs-params" style="line-height: 26px;">($class, $vars = [])</span><br>    </span>{<br>        <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">try</span> {<br><br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br>             * ReflectionClass Object<br>                (<br>                [name] =&gt; thinkApp<br>                )<br>             */</span><br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 这里就是之前文章提到的反射</span><br>            $reflect = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">new</span> ReflectionClass($class);<br><br><br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> ($reflect-&gt;hasMethod(<span class="hljs-string" style="color: #98c379; line-height: 26px;">'__make'</span>)) {<br>                $method = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">new</span> ReflectionMethod($class, <span class="hljs-string" style="color: #98c379; line-height: 26px;">'__make'</span>);<br><br>                <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> ($method-&gt;isPublic() &amp;&amp; $method-&gt;isStatic()) {<br>                    $args = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;bindParams($method, $vars);<br>                    <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> $method-&gt;invokeArgs(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">null</span>, $args);<br>                }<br>            }<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 通过反射获取thinkApp的构造函数</span><br>            $constructor = $reflect-&gt;getConstructor();<br><br>            $args = $constructor ? <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>-&gt;bindParams($constructor, $vars) : [];<br>            <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 从给出的参数创建一个新的类实例</span><br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> $reflect-&gt;newInstanceArgs($args);<br><br>        } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">catch</span> (ReflectionException $e) {<br>            <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">throw</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">new</span> ClassNotFoundException(<span class="hljs-string" style="color: #98c379; line-height: 26px;">'class not exists: '</span> . $class, $class);<br>        }<br>    }<br>

执行流程图

既然把代码都理清楚了,这时来理一下执行的流程图可以看的更清晰。

ThinkPHP容器之容器是如何返回实例的

坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在偌大互联网中咔咔的文章能带给你一丝丝帮助。我是咔咔,下期见。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享