PHP的Yii框架中YiiBase入口类的扩展写法示例
通过yiic.php自动创建一个应用后,入口文件初始代码如下:
<?php // change the following paths if necessary $yii=dirname(__file__).'/../yii/framework/yii.php'; $config=dirname(__file__).'/protected/config/main.php'; // remove the following lines when in production mode defined('yii_debug') or define('yii_debug',true); // specify how many levels of call stack should be shown in each log message defined('yii_trace_level') or define('yii_trace_level',3); require_once($yii); yii::createwebapplication($config)->run();
其中第三行引入了一个yii.php的文件,这个可以在yii核心目录里的framework/下找到,这个文件中定义了一个yii类,并且继承了yiibase类。
代码如下
require(dirname(__file__).'/yiibase.php'); /** * yii is a helper class serving common framework functionalities. * * it encapsulates {@link yiibase} which provides the actual implementation. * by writing your own yii class, you can customize some functionalities of yiibase. * * @author qiang xue <qiang.xue@gmail.com> * @package system * @since 1.0 */ class yii extends yiibase { }
而
yii::createwebapplication
这个方法实际上是在yiibase父类中定义的,所以,yii为我们预留了扩展的可能。我们只需要在yii.php中添加我们想要扩展的方法即可,在项目中直接使用 yii::方法名() 调用。
为了将项目代码和核心目录完全分离,我个人觉得在项目目录下使用另外一个yii.php来替代从核心目录中包含yii.php更加好。
这里我用了更加极端的方法,我直接将yii这个类定义在了入口文件,并扩展了一个全局工厂函数 instance()方法,请看代码:
<?php // change the following paths if necessary $yii=dirname(__file__).'/../yii/framework/yiibase.php'; $config=dirname(__file__).'/protected/config/main.php'; // remove the following lines when in production mode defined('yii_debug') or define('yii_debug',true); // specify how many levels of call stack should be shown in each log message defined('yii_trace_level') or define('yii_trace_level',3); require_once($yii); //扩展基类 class yii extends yiibase{ /** * 全局扩展方法:工厂函数 * @param type $alias 类库别名 */ static function instance($alias){ static $_class_ = array(); $key = md5($alias); if(!isset($_class_[$key])){ $_class_[$key] = self::createcomponent($alias); } return $_class_[$key]; } } yii::createwebapplication($config)->run();
这个类是在最后一行yii::createwebapplication()之前定义的,以保证yii类能正常使用(不要把这个类放在文件末尾,会出错。)
在项目中任何地方,使用$obj = yii::instance($alias);去实例化一个类,并且是单例模式。
yiibase中的两个比较重要的方法 (import,autoload)
然后看看yiibase中的import方法就知道这些静态变量是干嘛用的了:
/* yii::import() * $alias: 要导入的类名或路径 * $forceinclude false:只导入不include类文件,true则导入并include类文件 */ public static function import($alias, $forceinclude = false){ //yii把所有的依赖放入到这个全局的$_imports数组中,名字不能重复 //如果当前依赖已经被引入过了,那么直接返回 if (isset(self::$_imports[$alias])) { return self::$_imports[$alias]; } //class_exists和interface_exists方法的第二个参数的值为false表示不autoload if (class_exists($alias, false) || interface_exists($alias, false)) { return self::$_imports[$alias] = $alias; } //如果传进来的是一个php5.3版本的命名空间格式的类(例如:\a\b\c.php) if (($pos = strrpos($alias, '\\')) !== false) { //$namespace = a.b $namespace = str_replace('\\', '.', ltrim(substr($alias, 0, $pos), '\\')); //判断a.b这个路径是否存在,或者a.b只是alias里面的一个键,调用该方法返回这个键对应的值,比如'email' => realpath(__dir__ . '/../vendor/cornernote/yii-email-module/email') if (($path = self::getpathofalias($namespace)) !== false) { $classfile = $path . directory_separator . substr($alias, $pos + 1) . '.php'; if ($forceinclude) { if (is_file($classfile)) { require($classfile); } 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] = $alias; } else { self::$classmap[$alias] = $classfile; } return $alias; } else { // try to autoload the class with an autoloader if (class_exists($alias, true)) { return self::$_imports[$alias] = $alias; } else { throw new cexception(yii::t('yii', 'alias "{alias}" is invalid. make sure it points to an existing directory or file.', array('{alias}' => $namespace))); } } } if (($pos = strrpos($alias, '.')) === false) // a simple class name { // 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) { 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; } // $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); if (self::$enableincludepath && set_include_path('.' . path_separator . implode(path_separator, self::$_includepaths)) === false) { self::$enableincludepath = false; } 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))); } }
是的,上面这个方法最后就把要加载的东西都放到$_imports,$_includepaths中去了。这就是yii的import方法,好的,接下来我们看看autoload方法:
public static function autoload($classname, $classmaponly = false){ // 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(yii_path . self::$_coreclasses[$classname]); } elseif ($classmaponly) { return false; } 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); if (yii_debug && basename(realpath($classfile)) !== $classname . '.php') { throw new cexception(yii::t('yii', 'class name "{class}" does not match class file "{file}".', array( '{class}' => $classname, '{file}' => $classfile, ))); } break; } } } else { include($classname . '.php'); } } else // class name with namespace in php 5.3 { $namespace = str_replace('\\', '.', ltrim($classname, '\\')); if (($path = self::getpathofalias($namespace)) !== false) { include($path . '.php'); } else { return false; } }
return class_exists($classname, false) || interface_exists($classname, false); } return true;}
config文件中的 import 项里的类或路径在脚本启动中会被自动导入。用户应用里个别类需要引入的类可以在类定义前加入 yii::import() 语句。
推荐阅读
-
PHP的Yii框架中YiiBase入口类的扩展写法示例
-
Laravel框架中扩展函数、扩展自定义类的方法,laravel框架_PHP教程
-
PHP中迭代器的简单实现及Yii框架中的迭代器实现方法示例
-
PHP的Yii框架中YiiBase入口类的扩展写法示例_PHP
-
PHP的Yii框架中YiiBase入口类的扩展写法示例_PHP
-
Laravel框架中扩展函数、扩展自定义类的方法_php实例
-
yii2 用框架自带的User.php类时,此类中的beforeLogin具体执行的代码在哪里?需要自己书写?
-
PHP的Yii框架中YiiBase入口类的扩展写法示例
-
yii2 用框架自带的User.php类时,此类中的beforeLogin具体执行的代码在哪里?需要自己书写?
-
Laravel框架中扩展函数、扩展自定义类的方法_PHP