Home Backend Development PHP Tutorial yii源码分析四——非核心类的导入注册

yii源码分析四——非核心类的导入注册

Jun 13, 2016 pm 12:17 PM
alias config include self

yii源码分析4——非核心类的导入注册

转载请注明: TheViper http://www.cnblogs.com/TheViper 

在yii源码分析1中说到spl_autoload_register注册给定的函数作为 __autoload 的实现,在这里是autoload().

<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">function</span> autoload(<span style="color: #800080;">$className</span><span style="color: #000000;">) {        </span><span style="color: #0000ff;">include</span> self::<span style="color: #800080;">$_coreClasses</span> [<span style="color: #800080;">$className</span><span style="color: #000000;">];     }</span>
Copy after login

实际上这个autoload()是没有考虑非核心文件的引入的。比如,在app文件夹经常会有自定义的一些重要文件夹,比如'application.utils.*(工具类),'application.filters.*'(过滤类),'application.validators.*'(校验类)等。

在实际用的时候,是不用一个一个include的,直接new就可以了,yii已经帮我们做了include的工作。而这个工作就是在autoload()里面做的。

上面的代码很显然没有考虑非核心文件的引入,这是我的疏忽。

那yii是怎么帮我们引入非核心文件的?

这要从CApplication说起。

<span style="color: #0000ff;">abstract</span> <span style="color: #0000ff;">class</span> CApplication <span style="color: #0000ff;">extends</span><span style="color: #000000;"> CModule {    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$config</span> = <span style="color: #0000ff;">null</span><span style="color: #000000;">) {        </span><span style="color: #0000ff;">if</span> (<span style="color: #008080;">is_string</span> ( <span style="color: #800080;">$config</span><span style="color: #000000;"> ))            </span><span style="color: #800080;">$config</span> = <span style="color: #0000ff;">require</span> (<span style="color: #800080;">$config</span><span style="color: #000000;">);        Yii</span>::setApplication ( <span style="color: #800080;">$this</span> );<span style="color: #008000;">//</span><span style="color: #008000;">保存整个app实例</span>        <span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">isset</span> ( <span style="color: #800080;">$config</span> ['basePath'<span style="color: #000000;">] )) {            </span><span style="color: #800080;">$this</span>->setBasePath ( <span style="color: #800080;">$config</span> ['basePath'<span style="color: #000000;">] );            </span><span style="color: #0000ff;">unset</span> ( <span style="color: #800080;">$config</span> ['basePath'<span style="color: #000000;">] );        } </span><span style="color: #0000ff;">else</span>            <span style="color: #800080;">$this</span>->setBasePath ( 'protected'<span style="color: #000000;"> );        </span><span style="color: #008000;">//</span><span style="color: #008000;">设置别名,后面就可以用application表示basePath了</span>        Yii::setPathOfAlias ( 'application', <span style="color: #800080;">$this</span>-><span style="color: #000000;">getBasePath () );        </span><span style="color: #008000;">//</span><span style="color: #008000;">钩子,模块 预 初始化时执行,子类实现。不过这时,配置还没有写入框架</span>        <span style="color: #800080;">$this</span>-><span style="color: #000000;">preinit ();        </span><span style="color: #800080;">$this</span>-><span style="color: #000000;">registerCoreComponents ();        </span><span style="color: #008000;">//</span><span style="color: #008000;">父类实现</span>        <span style="color: #800080;">$this</span>->configure ( <span style="color: #800080;">$config</span><span style="color: #000000;"> );        </span><span style="color: #008000;">//</span><span style="color: #008000;">加载静态应用组件</span>        <span style="color: #800080;">$this</span>-><span style="color: #000000;">preloadComponents ();        </span><span style="color: #008000;">//</span><span style="color: #008000;">这才开始初始化模块</span>        <span style="color: #800080;">$this</span>-><span style="color: #000000;">init ();    }</span>
Copy after login

注意到里面的$this->configure ( $config );,$config是传入的配置文件,是一个数组,非核心文件的定义就是在这里面,比如引入工具类文件夹

<span style="color: #000000;">php</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">array</span><span style="color: #000000;"> (    </span>'basePath' => <span style="color: #008080;">dirname</span> ( <span style="color: #ff00ff;">__FILE__</span> ) . DIRECTORY_SEPARATOR . '..',    'import' => <span style="color: #0000ff;">array</span><span style="color: #000000;"> (        </span>'application.utils.*'<span style="color: #000000;">    )    );</span>?> 
Copy after login

然后在父类CModule

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> configure(<span style="color: #800080;">$config</span><span style="color: #000000;">) {        </span><span style="color: #0000ff;">if</span> (<span style="color: #008080;">is_array</span> ( <span style="color: #800080;">$config</span><span style="color: #000000;"> )) {            </span><span style="color: #0000ff;">foreach</span> ( <span style="color: #800080;">$config</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$key</span> => <span style="color: #800080;">$value</span><span style="color: #000000;"> )                </span><span style="color: #800080;">$this</span>-><span style="color: #800080;">$key</span> = <span style="color: #800080;">$value</span><span style="color: #000000;">;        }    }</span>
Copy after login

这里yii很"狡猾",它在CModule的父类CComponent中重写了__set()

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __set(<span style="color: #800080;">$name</span>,<span style="color: #800080;">$value</span><span style="color: #000000;">)    {        </span><span style="color: #800080;">$setter</span>='set'.<span style="color: #800080;">$name</span><span style="color: #000000;">;        </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">method_exists</span>(<span style="color: #800080;">$this</span>,<span style="color: #800080;">$setter</span><span style="color: #000000;">))            </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span>-><span style="color: #800080;">$setter</span>(<span style="color: #800080;">$value</span><span style="color: #000000;">);        </span><span style="color: #0000ff;">else</span>....<span style="color: #000000;">    }</span>
Copy after login

可以看到,如果CModule中如果有设置yii指定参数(比如import)的方法,就会调用它,而我之前裁剪的时候,把CModule中的setImport()删掉了。

另外可以看到basePath, params, modules, import, components 是yii保留的参数名。

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> setImport(<span style="color: #800080;">$aliases</span><span style="color: #000000;">)    {        </span><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$aliases</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$alias</span><span style="color: #000000;">)            Yii</span>::import(<span style="color: #800080;">$alias</span><span style="color: #000000;">);    }</span>
Copy after login

然后是YiiBase里面的import()

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">function</span> import(<span style="color: #800080;">$alias</span>, <span style="color: #800080;">$forceInclude</span> = <span style="color: #0000ff;">false</span><span style="color: #000000;">) {        </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">isset</span> ( self::<span style="color: #800080;">$_imports</span> [<span style="color: #800080;">$alias</span>] )) <span style="color: #008000;">//</span><span style="color: #008000;">是否已经存在路径</span>            <span style="color: #0000ff;">return</span> self::<span style="color: #800080;">$_imports</span> [<span style="color: #800080;">$alias</span><span style="color: #000000;">];                </span><span style="color: #0000ff;">if</span> (<span style="color: #008080;">class_exists</span> ( <span style="color: #800080;">$alias</span>, <span style="color: #0000ff;">false</span> ) || <span style="color: #008080;">interface_exists</span> ( <span style="color: #800080;">$alias</span>, <span style="color: #0000ff;">false</span> ))<span style="color: #008000;">//</span><span style="color: #008000;">类是否已经定义,针对如urlManager这样的已定义于$_coreClasses[]的类</span>            <span style="color: #0000ff;">return</span> self::<span style="color: #800080;">$_imports</span> [<span style="color: #800080;">$alias</span>] = <span style="color: #800080;">$alias</span><span style="color: #000000;">;        </span><span style="color: #0000ff;">if</span> ((<span style="color: #800080;">$pos</span> = <span style="color: #008080;">strrpos</span> ( <span style="color: #800080;">$alias</span>, '.' )) === <span style="color: #0000ff;">false</span>)         <span style="color: #008000;">//</span><span style="color: #008000;">直接是文件名</span><span style="color: #000000;">        {            </span><span style="color: #008000;">//</span><span style="color: #008000;"> try to autoload the class with an autoloader if $forceInclude is true</span>            <span style="color: #0000ff;">if</span> (<span style="color: #800080;">$forceInclude</span> && (Yii::autoload ( <span style="color: #800080;">$alias</span>, <span style="color: #0000ff;">true</span> ) || <span style="color: #008080;">class_exists</span> ( <span style="color: #800080;">$alias</span>, <span style="color: #0000ff;">true</span><span style="color: #000000;"> )))                self</span>::<span style="color: #800080;">$_imports</span> [<span style="color: #800080;">$alias</span>] = <span style="color: #800080;">$alias</span><span style="color: #000000;">;            </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$alias</span><span style="color: #000000;">;        }                </span><span style="color: #800080;">$className</span> = ( <span style="color: #0000ff;">string</span> ) <span style="color: #008080;">substr</span> ( <span style="color: #800080;">$alias</span>, <span style="color: #800080;">$pos</span> + 1<span style="color: #000000;"> );        </span><span style="color: #800080;">$isClass</span> = <span style="color: #800080;">$className</span> !== '*'<span style="color: #000000;">;        </span><span style="color: #008000;">//</span><span style="color: #008000;">是否为路径+类名</span>        <span style="color: #0000ff;">if</span> (<span style="color: #800080;">$isClass</span> && (<span style="color: #008080;">class_exists</span> ( <span style="color: #800080;">$className</span>, <span style="color: #0000ff;">false</span> ) || <span style="color: #008080;">interface_exists</span> ( <span style="color: #800080;">$className</span>, <span style="color: #0000ff;">false</span><span style="color: #000000;"> )))            </span><span style="color: #0000ff;">return</span> self::<span style="color: #800080;">$_imports</span> [<span style="color: #800080;">$alias</span>] = <span style="color: #800080;">$className</span><span style="color: #000000;">;        </span><span style="color: #008000;">//</span><span style="color: #008000;">获取真实路径</span>        <span style="color: #0000ff;">if</span> ((<span style="color: #800080;">$path</span> = self::getPathOfAlias ( <span style="color: #800080;">$alias</span> )) !== <span style="color: #0000ff;">false</span><span style="color: #000000;">) {            </span><span style="color: #008000;">//</span><span style="color: #008000;">是否以*结尾,如application.utils.*</span>            <span style="color: #0000ff;">if</span> (<span style="color: #800080;">$isClass</span><span style="color: #000000;">) {                </span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$forceInclude</span><span style="color: #000000;">) {                    </span><span style="color: #0000ff;">if</span> (<span style="color: #008080;">is_file</span> ( <span style="color: #800080;">$path</span> . '.php'<span style="color: #000000;"> ))                        </span><span style="color: #0000ff;">require</span> (<span style="color: #800080;">$path</span> . '.php'<span style="color: #000000;">);                    </span><span style="color: #0000ff;">else</span>                        <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> CException ( Yii::t ( 'yii', 'Alias "{alias}" is invalid. Make sure it points to an existing PHP file and the file is readable.', <span style="color: #0000ff;">array</span><span style="color: #000000;"> (                                </span>'{alias}' => <span style="color: #800080;">$alias</span><span style="color: #000000;">                         ) ) );                    self</span>::<span style="color: #800080;">$_imports</span> [<span style="color: #800080;">$alias</span>] = <span style="color: #800080;">$className</span><span style="color: #000000;">;                } </span><span style="color: #0000ff;">else</span><span style="color: #000000;">                    self</span>::<span style="color: #800080;">$classMap</span> [<span style="color: #800080;">$className</span>] = <span style="color: #800080;">$path</span> . '.php'<span style="color: #000000;">;                </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$className</span><span style="color: #000000;">;            } </span><span style="color: #0000ff;">else</span>             <span style="color: #008000;">//</span><span style="color: #008000;"> a directory</span><span style="color: #000000;">            {                </span><span style="color: #0000ff;">if</span> (self::<span style="color: #800080;">$_includePaths</span> === <span style="color: #0000ff;">null</span><span style="color: #000000;">) {                    self</span>::<span style="color: #800080;">$_includePaths</span> = <span style="color: #008080;">array_unique</span> ( <span style="color: #008080;">explode</span> ( PATH_SEPARATOR, <span style="color: #008080;">get_include_path</span><span style="color: #000000;"> () ) );                    </span><span style="color: #0000ff;">if</span> ((<span style="color: #800080;">$pos</span> = <span style="color: #008080;">array_search</span> ( '.', self::<span style="color: #800080;">$_includePaths</span>, <span style="color: #0000ff;">true</span> )) !== <span style="color: #0000ff;">false</span><span style="color: #000000;">)                        </span><span style="color: #0000ff;">unset</span> ( self::<span style="color: #800080;">$_includePaths</span> [<span style="color: #800080;">$pos</span><span style="color: #000000;">] );                }                                </span><span style="color: #008080;">array_unshift</span> ( self::<span style="color: #800080;">$_includePaths</span>, <span style="color: #800080;">$path</span><span style="color: #000000;"> );                                </span><span style="color: #0000ff;">if</span> (self::<span style="color: #800080;">$enableIncludePath</span> && <span style="color: #008080;">set_include_path</span> ( '.' . PATH_SEPARATOR . <span style="color: #008080;">implode</span> ( PATH_SEPARATOR, self::<span style="color: #800080;">$_includePaths</span> ) ) === <span style="color: #0000ff;">false</span><span style="color: #000000;">)                    self</span>::<span style="color: #800080;">$enableIncludePath</span> = <span style="color: #0000ff;">false</span><span style="color: #000000;">;                </span><span style="color: #0000ff;">return</span> self::<span style="color: #800080;">$_imports</span> [<span style="color: #800080;">$alias</span>] = <span style="color: #800080;">$path</span><span style="color: #000000;">;            }        }    }</span>
Copy after login

 

一系列的判断,最后走到最后的else,将path写入到$_imports,这时仍然没有include.

include在autoload()

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">function</span> autoload(<span style="color: #800080;">$className</span><span style="color: #000000;">)    {        </span><span style="color: #008000;">//</span><span style="color: #008000;"> use include so that the error PHP file may appear</span>        <span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(self::<span style="color: #800080;">$classMap</span>[<span style="color: #800080;">$className</span><span style="color: #000000;">]))            </span><span style="color: #0000ff;">include</span>(self::<span style="color: #800080;">$classMap</span>[<span style="color: #800080;">$className</span><span style="color: #000000;">]);        </span><span style="color: #0000ff;">elseif</span>(<span style="color: #0000ff;">isset</span>(self::<span style="color: #800080;">$_coreClasses</span>[<span style="color: #800080;">$className</span><span style="color: #000000;">]))            </span><span style="color: #0000ff;">include</span>(self::<span style="color: #800080;">$_coreClasses</span>[<span style="color: #800080;">$className</span><span style="color: #000000;">]);        </span><span style="color: #0000ff;">else</span><span style="color: #000000;">        {            </span><span style="color: #008000;">//</span><span style="color: #008000;"> include class file relying on include_path</span>            <span style="color: #0000ff;">if</span>(<span style="color: #008080;">strpos</span>(<span style="color: #800080;">$className</span>,'\\')===<span style="color: #0000ff;">false</span>)  <span style="color: #008000;">//</span><span style="color: #008000;"> class without namespace</span><span style="color: #000000;">            {                </span><span style="color: #0000ff;">if</span>(self::<span style="color: #800080;">$enableIncludePath</span>===<span style="color: #0000ff;">false</span><span style="color: #000000;">)                {                    </span><span style="color: #0000ff;">foreach</span>(self::<span style="color: #800080;">$_includePaths</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$path</span><span style="color: #000000;">)                    {                        </span><span style="color: #800080;">$classFile</span>=<span style="color: #800080;">$path</span>.DIRECTORY_SEPARATOR.<span style="color: #800080;">$className</span>.'.php'<span style="color: #000000;">;                        </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">is_file</span>(<span style="color: #800080;">$classFile</span><span style="color: #000000;">))                        {                            </span><span style="color: #0000ff;">include</span>(<span style="color: #800080;">$classFile</span><span style="color: #000000;">);                            </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;                        }                    }                }                </span><span style="color: #0000ff;">else</span>                    <span style="color: #0000ff;">include</span>(<span style="color: #800080;">$className</span>.'.php'<span style="color: #000000;">);            }            </span><span style="color: #0000ff;">return</span> <span style="color: #008080;">class_exists</span>(<span style="color: #800080;">$className</span>,<span style="color: #0000ff;">false</span>) || <span style="color: #008080;">interface_exists</span>(<span style="color: #800080;">$className</span>,<span style="color: #0000ff;">false</span><span style="color: #000000;">);        }        </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #000000;">;    }</span>
Copy after login

 

如果需要include的是非核心文件,那这里的$className只是一个alias,即文件名的前缀。

裁剪的yii http://files.cnblogs.com/TheViper/framework.zip

如果您觉得本文的内容对您有所帮助,您可以打赏我:

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Roblox: Bubble Gum Simulator Infinity - How To Get And Use Royal Keys
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusion System, Explained
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers Of The Witch Tree - How To Unlock The Grappling Hook
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1666
14
PHP Tutorial
1273
29
C# Tutorial
1253
24
Why NameResolutionError(self.host, self, e) from e and how to solve it Why NameResolutionError(self.host, self, e) from e and how to solve it Mar 01, 2024 pm 01:20 PM

The reason for the error is NameResolutionError(self.host,self,e)frome, which is an exception type in the urllib3 library. The reason for this error is that DNS resolution failed, that is, the host name or IP address attempted to be resolved cannot be found. This may be caused by the entered URL address being incorrect or the DNS server being temporarily unavailable. How to solve this error There may be several ways to solve this error: Check whether the entered URL address is correct and make sure it is accessible Make sure the DNS server is available, you can try using the "ping" command on the command line to test whether the DNS server is available Try accessing the website using the IP address instead of the hostname if behind a proxy

What is the difference between the root and alias directives in Nginx configuration? What is the difference between the root and alias directives in Nginx configuration? May 12, 2023 pm 12:16 PM

Both root and alias can be defined in the location module, and are used to specify the real path of the requested resource, for example: location/i/{root/data/w3;} requests http://foofish.net/i/top.gif When this address is used, the corresponding real resource in the server is the /data/w3/i/top.gif file. Note: The real path is the value specified by root plus the value specified by location. And alias is just like its name. The path specified by alias is the alias of location. No matter how the value of location is written, the real path of the resource is the path specified by alias, such as

How to fix error 0xC00CE556 returned by the .NET parser How to fix error 0xC00CE556 returned by the .NET parser Apr 25, 2023 am 08:34 AM

While installing a new version of an application, Windows may display this error message "An error occurred while parsing C:\\Windows\Microsoft.Net\Framework\v2.0.50727\Config\machine.configParser returned error 0xC00CE556". This problem also occurs when your system boots. No matter what situation you encounter this problem, .NETFramework is the real culprit behind the scenes. There are some very simple fixes you can use to stop this error code from appearing again. Fix 1 – Replace corrupted files You can easily replace corrupted ma from the original directory

What is the difference between php include and include_once What is the difference between php include and include_once Mar 22, 2023 am 10:38 AM

When we write web pages using PHP, sometimes we need to include code from other PHP files in the current PHP file. At this time, you can use the include or include_once function to implement file inclusion. So, what is the difference between include and include_once?

How to use ThinkPHP\Config for configuration management in php? How to use ThinkPHP\Config for configuration management in php? May 31, 2023 pm 02:31 PM

With the continuous development of the PHP language, ThinkPHP, which is widely used in the PHP back-end framework, is also constantly improving. As business scenarios become increasingly complex, the demand for configuration management in ThinkPHP is also increasing. In this context, ThinkPHP provides rich configuration management functions. Today we will introduce how to implement configuration management through ThinkPHPConfig. 1. Introduction to ThinkPHPConfig ThinkPHPConfig is Thin

How to use self in Python How to use self in Python May 17, 2023 pm 10:40 PM

Before introducing the usage of self in Python, let’s first introduce the classes and instances in Python. We know that the most important concepts of object-oriented are classes and instances. Classes are abstract templates, such as abstract things like students. , can be represented by a Student class. Instances are specific "objects" created based on classes. Each object inherits the same methods from the class, but its data may be different. 1. Take the Student class as an example. In Python, the class is defined as follows: classStudent(object):pass(Object) indicates which class the class inherits from. The Object class is all

How does php use CodeIgniter\Config for configuration management? How does php use CodeIgniter\Config for configuration management? Jun 02, 2023 pm 06:01 PM

1. Introduction to CodeIgniter CodeIgniter is a lightweight and comprehensive PHP development framework designed to provide web developers with fast and powerful tools to build web applications. It is an open source framework that uses the MVC architecture pattern to achieve rapid development and basic functions, while supporting a variety of databases. 2. Introduction to the Config library The Config library is a component in the CodeIgniter framework and is used to configure and manage code. The Config library contains many

Example analysis of nginx, apache's alias and authentication functions Example analysis of nginx, apache's alias and authentication functions May 24, 2023 pm 11:10 PM

First, let’s take a look at how to configure the apache alias: Copy the code as follows: documentroot/www/jb51.net/www This is the root directory of the virtual host, but phpmyadmin is not in this directory and wants to access it. servernamewww.jb51.netserveraliasjb51.netalias/sdb"/www/public/phpmyadmin/" requires the alias function, ://www.jb51.net/sdb which is much safer. optionsindexesfollowsymlinksallowove

See all articles