Home >php教程 >PHP开发 >Yii Framework Analysis (3) - Class Loading Mechanism and Management, Configuration, Access and Creation of Application Components

Yii Framework Analysis (3) - Class Loading Mechanism and Management, Configuration, Access and Creation of Application Components

黄舟
黄舟Original
2016-12-27 11:11:261422browse

The entry script of the Yii application references the Yii class. The definition of the Yii class:

class Yii extends YiiBase
{
}

In the application created by yiic, the Yii class is just the "vest" of the YiiBase class. We can also customize our own according to our needs. Yii category.

Yii (i.e. YiiBase) is a "helper class" that provides static and global access to the entire application.

Several static members of the Yii class:
$_aliases: stores the real paths corresponding to system aliases
$_imports:
$_classes:
$_includePaths php include paths
$_app: CWebApplication object, accessed through Yii::app()
$_logger: System log object
$_app object is created by Yii::createWebApplication() method.

Class automatic loading

Yii is based on the autoload mechanism of php5 to provide the automatic loading function of classes. The automatic loader is the static method autoload() of the YiiBase class.

When the program uses new to create an object or access a static member of a class, PHP passes the class name to the class loader, and the class loader completes the include of the class file.

The autoload mechanism implements the "on-demand import" of classes, which means that the system includes the class file only when it accesses the class.

The static member $_coreClasses of the YiiBase class pre-stores Yii's own core class name and the corresponding class file path. Classes used in other Yii applications can be imported using Yii::import(). Yii::import() stores the single class and corresponding class files in $_classes, and adds the path represented by the * wildcard character to php include_path. . Class files or directories imported by Yii::import() are recorded in $_imports to avoid multiple imports.

/* Yii::import()
* $alias: 要导入的类名或路径
* $forceInclude false:只导入不include类文件,true则导入并include类文件
*/
public static function import($alias,$forceInclude=false)
{
    // 先判断$alias是否存在于YiiBase::$_imports[] 中,已存在的直接return, 避免重复import。
    if(isset(self::$_imports[$alias])) // previously imported
        return self::$_imports[$alias];
    // $alias类已定义,记入$_imports[],直接返回
    if(class_exists($alias,false) || interface_exists($alias,false))
        return self::$_imports[$alias]=$alias;
    // 已定义于$_coreClasses[]的类,或名字中不含.的类,记入$_imports[],直接返回
    if(isset(self::$_coreClasses[$alias]) || ($pos=strrpos($alias,’.'))===false) // a simple class name
    {
        self::$_imports[$alias]=$alias;
        if($forceInclude)
        {
            if(isset(self::$_coreClasses[$alias])) // a core class
                require(YII_PATH.self::$_coreClasses[$alias]);
            else
                require($alias.’.php’);
        }
        return $alias;
    }
    // 产生一个变量 $className,为$alias最后一个.后面的部分
    // 这样的:’x.y.ClassNamer’
    // $className不等于 ‘*’, 并且ClassNamer类已定义的,????? ClassNamer’ 记入 $_imports[],直接返回
    if(($className=(string)substr($alias,$pos+1))!==’*’ 
            && (class_exists($className,false) || interface_exists($className,false)))
        return self::$_imports[$alias]=$className;
    // $alias里含有别名,并转换真实路径成功
    if(($path=self::getPathOfAlias($alias))!==false)
    {
        // 不是以*结尾的路径(单类)
        if($className!==’*')
        {
            self::$_imports[$alias]=$className;
            if($forceInclude)
                require($path.’.php’);
            else
                // 类名与真实路径记入$_classes数组
                self::$_classes[$className]=$path.’.php’;
            return $className;
        }
        // $alias是’system.web.*’这样的已*结尾的路径,将路径加到include_path中
        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);
            set_include_path(‘.’.PATH_SEPARATOR.implode(PATH_SEPARATOR,self::$_includePaths));
            return self::$_imports[$alias]=$path;
         }
    }
    else
        throw new CException(Yii::t(‘yii’,'Alias “{alias}” is invalid. Make sure it points to an existing directory or file.’,array(‘{alias}’=>$alias)));
}

Then take a look at the processing of the YiiBase::autoload() function:

public static function autoload($className)
{
    // $_coreClasses中配置好的类直接引入
    if(isset(self::$_coreClasses[$className]))
        include(YII_PATH.self::$_coreClasses[$className]);
    // $_classes 中登记的单类直接引入
    else if(isset(self::$_classes[$className]))
        include(self::$_classes[$className]);
    else
    {
        // 其他的认为文件路径以记入 include_path 里,以$className.’.php’直接引入
        include($className.’.php’);
        return class_exists($className,false) || interface_exists($className,false);
    }
    return true;
}

The classes or paths in the import item in the system configuration file will be automatically imported during script startup. For classes that need to be imported into individual classes in user applications, the Yii::import() statement can be added before the class definition.

Application component management

As mentioned earlier, Yii's CComponent class provides access interfaces to component properties, events, and behaviors, and CComponent's subclass CModule also provides application components. management.

The application component must be an instance of the IApplicationComponent interface and needs to implement the init() and getIsInitialized() methods of the interface. init() will be automatically called after applying component initialization parameters.

Yii's own functional modules are provided through application components, such as the common Yii::app()->user, Yii::app()->request, etc. Users can also define application components.

As the parent class of the Yii::app() object (CWebApplication), CModule provides complete component life cycle management, including component creation, initialization, object storage, etc.

Each application component is identified by a string name and accessed through the __get() method of the CModule class.

The $_components[] member of the CModule class stores the object instance of the application component ($name => $object), and $_componentConfig[] stores the class name and initialization parameters of the application component.

When using an application component, first set the class name and initialization parameters of the component in $_componentConfig. When accessing the component for the first time, CModule will automatically create an application component object instance and initialize the given parameters. Then the init() method of the application component is called.

Yii::app() object's class CWebApplication and its parent class CApplication are pre-configured with application components used by the system itself: urlManager, request, session, assetManager, user, themeManager, authManager, clientScript, coreMessages, db, messages, errorHandler, securityManager, statePersister.

We can modify the parameters of the system application components or configure new application components in the components project of the system configuration file.

CModule is not responsible for the creation of application component instances, but is completed by the Yii::createComponent() static method.

The parameter $config of createComponent() can be a string of class name or an array storing class name and initialization parameters.

Configuration of application components

The configuration of application components is stored in the components item in the system $config variable (config/main.php):

// application components
‘components’=>array(
    ‘log’=>array(
        ‘class’=>’CLogRouter’,
        ‘routes’=>array(
            array(
                ‘class’=>’CFileLogRoute’,
                ‘levels’=>’error, warning’,
            ),
         ),
    ),
    ‘user’=>array(
    // enable cookie-based authentication
        ‘allowAutoLogin’=>true,
    ),
),

$config The components items are processed in the constructor of CApplication:

$this->configure($config);

The processing of the configure() function is very simple:

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

Each item in $config is passed as an attribute to the setXXX() attribute setting method of the $_app object, where the 'components' item is processed by setComponents(), the parent class of CModule in CWebApplication.

setComponents() stores the class name and initialization parameters in the 'components' item into $_componentConfig[]:

public function setComponents($components)
{
    // $config 里的’components’每一项
    foreach($components as $id=>$component)
    {
        if($component instanceof IApplicationComponent)
            $this->setComponent($id,$component);
        // $_componentConfig里已经存在配置,合并$component
        else if(isset($this->_componentConfig[$id]))
            $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
        // 在$_componentConfig里新建项目
        else
            $this->_componentConfig[$id]=$component;
    }
}

Access to application components

CModule类重载了CComponent的__get()方法,优先访问应用组件对象。

public function __get($name)
{
    if($this->hasComponent($name))
        return $this->getComponent($name);
    else
        return parent::__get($name);
}

hasComponent() 判断$_components[]中是否已存在组件实例,或$_componentConfig[]中存在组件配置信息。

public function hasComponent($id)
{
    return isset($this->_components[$id]) || isset($this->_componentConfig[$id]);
}

getComponent() 判断组件实例已经存在于$_components[]中,则直接返回对象。
否则根据$_componentConfig[]里的组件配置数据调用 Yii::createComponent() 来创建组件,并将对象存入$_components[]中然后返回。

public function getComponent($id,$createIfNull=true)
{
    if(isset($this->_components[$id]))
        return $this->_components[$id];
    else if(isset($this->_componentConfig[$id]) && $createIfNull)
    {
        $config=$this->_componentConfig[$id];
        unset($this->_componentConfig[$id]);
        if(!isset($config['enabled']) || $config['enabled'])
        {
            Yii::trace(“Loading \”$id\” application component”,’system.web.CModule’);
            unset($config['enabled']);
            $component=Yii::createComponent($config);
            $component->init();
            return $this->_components[$id]=$component;
        }
    }
}

应用组件的创建

Yii::createComponent() 来完成应用组件的创建

public static function createComponent($config)
{
    if(is_string($config))
    {
        $type=$config;
        $config=array();
    }
    else if(isset($config['class']))
    {
        $type=$config['class'];
        unset($config['class']);
    }
    else
        throw new CException(Yii::t(‘yii’,'Object configuration must be an array containing a “class” element.’));
 
    if(!class_exists($type,false))
        $type=Yii::import($type,true);
 
    if(($n=func_num_args())>1)
    {
        $args=func_get_args();
        if($n===2)
            $object=new $type($args[1]);
        else if($n===3)
            $object=new $type($args[1],$args[2]);
        else if($n===4)
            $object=new $type($args[1],$args[2],$args[3]);
        else
        {
            unset($args[0]);
            $class=new ReflectionClass($type);
            // Note: ReflectionClass::newInstanceArgs() is available for PHP 5.1.3+
            // $object=$class->newInstanceArgs($args);
            $object=call_user_func_array(array($class,’newInstance’),$args);
        }
    }
    else
        $object=new $type;
 
    foreach($config as $key=>$value)
    $object->$key=$value;
 
    return $object;
}

 以上就是Yii框架分析(三)——类加载机制及应用组件的管理、配置、访问、创建的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Statement:
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