·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> php网站开发 >> yii源码分析4——非核心类的导入注册

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

作者:佚名      php网站开发编辑:admin      更新时间:2022-07-23
yii源码分析4——非核心类的导入注册

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

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

public static function autoload($className) {        include self::$_coreClasses [$className];     }

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

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

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

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

这要从CApplication说起。

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

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

<?phpreturn array (    'basePath' => dirname ( __FILE__ ) . DIRECTORY_SEPARATOR . '..',    'import' => array (        'application.utils.*'    )    );?> 

然后在父类CModule

    public function configure($config) {        if (is_array ( $config )) {            foreach ( $config as $key => $value )                $this->$key = $value;        }    }

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

    public function __set($name,$value)    {        $setter='set'.$name;        if(method_exists($this,$setter))            return $this->$setter($value);        else....    }

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

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

    public function setImport($aliases)    {        foreach($aliases as $alias)            Yii::import($alias);    }

然后是YiiBase里面的import()

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

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

include在autoload()

    public static function autoload($className)    {        // use include so that the error PHP file may appear        if(isset(self::$classMap[$className]))            include(self::$classMap[$className]);        elseif(isset(self::$_coreClasses[$className]))            include(self::$_coreClasses[$className]);        else        {            // include class file relying on include_path            if(strpos($className,'\\')===false)  // class without namespace            {                if(self::$enableIncludePath===false)                {                    foreach(self::$_includePaths as $path)                    {                        $classFile=$path.DIRECTORY_SEPARATOR.$className.'.php';                        if(is_file($classFile))                        {                            include($classFile);                            break;                        }                    }                }                else                    include($className.'.php');            }            return class_exists($className,false) || interface_exists($className,false);        }        return true;    }

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

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