程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> yii源碼分析4——非核心類的導入注冊,yii源碼

yii源碼分析4——非核心類的導入注冊,yii源碼

編輯:關於PHP編程

yii源碼分析4——非核心類的導入注冊,yii源碼


轉載請注明: TheViper http://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是傳入的配置文件,是一個數組,非核心文件的定義就是在這裡面,比如引入工具類文件夾

<?php
return 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,即文件名的前綴。

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

如果您覺得本文的內容對您有所幫助,您可以打賞我:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved