简要剖析PHP的Yii框架的组件化机制的基本知识


Posted in PHP onMarch 17, 2016

组件是 Yii 应用的主要基石。是 yii\base\Component 类或其子类的实例。三个用以区分它和其它类的主要功能有:

  • 属性(Property)
  • 事件(Event)
  • 行为(Behavior)

或单独使用,或彼此配合,这些功能的应用让 Yii 的类变得更加灵活和易用。以小部件 yii\jui\DatePicker 来举例,这是个方便你在 视图中生成一个交互式日期选择器的 UI 组件:

use yii\jui\DatePicker;

echo DatePicker::widget([
  'language' => 'zh-CN',
  'name' => 'country',
  'clientOptions' => [
    'dateFormat' => 'yy-mm-dd',
  ],
]);

这个小部件继承自 yii\base\Component,它的各项属性改写起来会很容易。

正是因为组件功能的强大,他们比常规的对象(Object)稍微重量级一点,因为他们要使用额外的内存和 CPU 时间来处理 事件 和 行为 。如果你不需要这两项功能,可以继承 yii\base\Object 而不是 yii\base\Component。这样组件可以像普通 PHP 对象一样高效,同时还支持属性(Property)功能。

当继承 yii\base\Component 或 yii\base\Object 时,推荐你使用如下的编码风格:

若你需要重写构造方法(Constructor),传入 $config 作为构造器方法最后一个参数,然后把它传递给父类的构造方法。
永远在你重写的构造方法结尾处调用一下父类的构造方法。
如果你重写了 yii\base\Object::init() 方法,请确保你在 init 方法的开头处调用了父类的 init 方法。
例子如下:

namespace yii\components\MyClass;

use yii\base\Object;

class MyClass extends Object
{
  public $prop1;
  public $prop2;

  public function __construct($param1, $param2, $config = [])
  {
    // ... 配置生效前的初始化过程

    parent::__construct($config);
  }

  public function init()
  {
    parent::init();

    // ... 配置生效后的初始化过程
  }
}

另外,为了让组件可以在创建实例时能被正确配置,请遵照以下操作流程:

$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
// 方法二:
$component = \Yii::createObject([
  'class' => MyClass::className(),
  'prop1' => 3,
  'prop2' => 4,
], [1, 2]);

补充:尽管调用 Yii::createObject() 的方法看起来更加复杂,但这主要因为它更加灵活强大,它是基于依赖注入容器实现的。
yii\base\Object 类执行时的生命周期如下:

构造方法内的预初始化过程。你可以在这儿给各属性设置缺省值。
通过 $config 配置对象。配置的过程可能会覆盖掉先前在构造方法内设置的默认值。
在 yii\base\Object::init() 方法内进行初始化后的收尾工作。你可以通过重写此方法,进行一些良品检验,属性的初始化之类的工作。
对象方法调用。
前三步都是在对象的构造方法内发生的。这意味着一旦你获得了一个对象实例,那么它就已经初始化就绪可供使用。

应用程序CWebApplication组件
在说明Yii中各个组件使用方法前,先了解最重要的一个组件CWebApplication。CWebApplication即应用程序对象,它的根类也是CComponent,故它也是一个组件,具有Yii组件的共同特征。
具体来说,CWebApplication组件的主要作用是根据配置文件,加载必要的辅助组件,并在这些组件的帮助下(如urlManager)创建并运行控制器。故也将其称为前端控制器。
我们可以在配置文件中指定CWebApplication组件本身的配置参数,这些参数被设置为其公共成员变量,或是自动调用setter方法设置属性,这个特性可以在CWebApplication的构造函数中发现:$this->configure($config);
如在配置文件protected/config/main.php全局中指定:

'charset' => 'utf-8',

这实际是设置当前应用程序的charset公共属性(在CApplication中声明)而如果在配置文件中指定'language' => 'zh_cn', 我们发现CWebApplication及其所有上级类均未声明$language属性,这时将使用setter模式方法即setlanuage(此方法定义在CApplication类中)。
OK,了解这个特性之后,我们就可以明白在配置文件中可以配置的属性:

  • CWebApplication及其所有上级类的公共成员变量
  • CWebApplication及其所有上级类的setter方法指定的属性当然我们也可以通过继承CWebApplication构造自己的应用程序类。

CWebApplication的继承层次为:CApplication -> CModule -> CComponent, 我们将默认的配置文件中常见的配置项及其生效位置予以说明:

  • basePath :  CApplication::setBasePath()
  • name: CApplication::$name
  • preload: CModule::$preload
  • import: CModule::setImport()
  • defaultController: CWebApplication::$defaultController
  • components: CModule::setComponents()

类似地,再列出几个默认配置文件中并未列出的配置项:timezone: CApplication::setTimeZone()  #配置时区

再例如,如果我们继承CWebApplication, 扩展自己的应用程序类myApp, 并定义方法setError_reporting(不区分大小写), 那么就可以直接在配置文件中指定error_reporting选项。
辅助组件可以将CWebApplication组件视为一部机器,那么辅助组件就可以视为组成这部机器的各个零件,没有零件的正确组合,机器就无法正常工作,这在Yii中也是同样的概念。而一些组件对整部机器的运转是必须的,这就是核心组件。在应用程序对象构造后,Yii会将辅助组件基本信息进行登记(组件名称与类名,属性配置的对照表),以供后续使用,对web应用程序而言,存在以下核心组件(通过CWebApplication::registerCoreComponents,CApplication::registerCoreComponents注册):

CWebApplication::registerCoreComponents中注册的核心组件

简要剖析PHP的Yii框架的组件化机制的基本知识

CApplication::registerCoreComponents中注册的核心组件

简要剖析PHP的Yii框架的组件化机制的基本知识

配置文本中注册的核心组件:log CLogRouter 日志路由管理器
以上标记为红色的条目,是最重要的辅助组件,其它的核心组件我们未必会使用到。
如何定义辅助组件的属性?通过在配置文件protected/config/main.php中设置components项的值,实现组件属性定义。这里的定义主要是三个要素:指定组件的名称(核心组件已经预先设置)、指定组件使用的类(核心组件无须定义),组件的属性(可选、视情况而定)
如以下配置:

'components' => array(
'db' => array(
'class' => 'myCDbConnection',
'connnectionString' => 'mysql:host=localhost;dbname=test;charset=utf8',
'user' => 'root',
),
);

就设置了db组件使用的类为myCDbConnection, 并且在后面指定了连接串及账号等信息。提示: myCDbConnection类可能就是通过继承CDbConnection类定义。核心组件无须指定class参数(因为已经预先定义好)
问题:如何得知某个组件可配置的属性?这个问题至关重要,如果我们掌握了规律,就可以举一反三,所有组件的配置均可以灵活设定。授之以鱼不如授之以渔。在本节会说明通用的方法。要得知组件的所有可定义属性,按以下步骤进行:
1. 组件所使用的类是什么?(无论是核心组件还是自定义组件)
2. 组件类的公共成员变量都有哪些?(注意从父类继承而来的公共成员变量)
3. 组件类都有哪些settter方法?(注意从父类继承而来的方法)
明白了以上三个要点,我们就可以按规律定义组件的属性,比如对最重要的db组件,我们发现这是一个核心组件,使用的类为CDbConnection, 我们查阅这个类的定义文件,发现这个类的公共成员变量有:

$connectionString;

  • $username='';
  • $password='';
  • $autoConnect=true;
  • $charset;
  • $emulatePrepare;
  • $tablePrefix;
  • $initSQLs;
  • ... ...

setter方法定义的属性:

  • setActive($value)
  • setAttributes($values)
  • setAutoCommit($value)
  • setColumnCase($value)
  • setNullConversion($value)
  • setPersistent($value)

提示:setter方法定义的属性名称不区分大小写以上所列的属性,均可以在配置文件中指定,具体每个属性的作用,请参阅Yii类文件的详细注释(Yii代码的注释也是相当棒,通俗易懂,而又很详细)

再来一个例子,定义urlManager组件的属性这个组件使用的类为CUrlManager, 我们查阅它的属性:

  • $rules=array();
  • $urlSuffix='';
  • $showScriptName=true;
  • $appendParams=true;
  • $routeVar='r';
  • $caseSensitive=true;

通过setter方法定义的属性:

  • setUrlFormat($value)
  • setBaseUrl($value)

即urlManager组件的上述属性可以在配置文件中定义(每项配置的作用请参阅其注释)。其它组件的配置均可按上述方法处理。

如何使用组件应用程序运行后,会将所有已经定义过的组件注册(并未实例化)到CWebApplication对象上,同时CWebApplication应用程序对象会被注册到Yii::$_app,在程序的任何位置均可通过Yii::app()得到当前应用程序对象引用,再通过$app对象得到组件实例引用,如:Yii::app()->getComponent('urlManager');  #会查找组件配置并实例化之Yii::app()->urlManager;  #通过CModule::__get()魔术方法实现
如何自定义组件?这是很常见的需求,比如我们可能希望db组件(数据库连接)使用我们自定义的类,也或者我们希望使用多个数据库连接,这种情况下就需要自定义组件,使用多数据库的例子:

components=>array(
'db' => array(
... ...
),
'mydb'=>array(
'class' => 'myDbConnection',
'connectionString' => 'mysql:host=localhost;dbname=test;charset=utf8',
'tablePrefix' => 'cdb_',
'username' => 'root',
),
),
修改默认的db组件所使用的类:
components=>array(
'db' => array(
'class' => 'myDbConnection',
... ...
),
),

经过本文的分析,我是深切理解了Yii组件化机制给应用程序带来的极大的扩展性,哈哈哈哈~

PHP 相关文章推荐
针对初学PHP者的疑难问答(2)
Oct 09 PHP
中篇:安装及配置PHP
Dec 13 PHP
php+mysql 实现身份验证代码
Mar 24 PHP
让的PHP代码飞起来的40条小技巧(提升php效率)
Apr 12 PHP
PHP查询MySQL大量数据的时候内存占用分析
Jul 22 PHP
php中error与exception的区别及应用
Jul 28 PHP
php强制运行广告的方法
Dec 01 PHP
php页面函数设置超时限制的方法
Dec 01 PHP
PHP简单获取视频预览图的方法
Mar 12 PHP
Yii快速入门经典教程
Dec 28 PHP
PHP中session跨子域的三种实现方法
Jul 25 PHP
kindeditor 加入七牛云上传的实例讲解
Nov 12 PHP
PHP的Yii框架中YiiBase入口类的扩展写法示例
Mar 17 #PHP
Symfony控制层深入详解
Mar 17 #PHP
详解PHP的Yii框架的运行机制及其路由功能
Mar 17 #PHP
深入解析PHP的Yii框架中的event事件机制
Mar 17 #PHP
全面解读PHP的Yii框架中的日志功能
Mar 17 #PHP
Symfony核心类概述
Mar 17 #PHP
使用symfony命令创建项目的方法
Mar 17 #PHP
You might like
PHP网页游戏学习之Xnova(ogame)源码解读(十三)
2014/06/26 PHP
PHP魔术方法的使用示例
2015/06/23 PHP
php连接mysql数据库
2017/03/21 PHP
Laravel-admin之修改操作日志的方法
2019/09/30 PHP
javascript获取鼠标位置部分的实例代码(兼容IE,FF)
2013/08/05 Javascript
基于promise.js实现nodejs的promises库
2014/07/06 NodeJs
javascript实现window.print()去除页眉页脚
2014/12/30 Javascript
JavaScript中的DSL元编程介绍
2015/03/15 Javascript
用JavaScript实现页面重定向功能的教程
2015/06/04 Javascript
javascript实现数组中的内容随机输出
2015/08/11 Javascript
jquery mobile 移动web(5)
2015/12/20 Javascript
js使用原型对象(prototype)需要注意的地方
2017/08/28 Javascript
jQuery实现文件编码成base64并通过AJAX上传的方法
2018/04/12 jQuery
vue实现点击当前标签高亮效果【推荐】
2018/06/22 Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
2019/07/23 Javascript
Vue自定义指令结合阿里云OSS优化图片的实现方法
2019/11/12 Javascript
javascript实现视频弹幕效果(两个版本)
2019/11/28 Javascript
Python实现的百度站长自动URL提交小工具
2014/06/27 Python
python装饰器深入学习
2018/04/06 Python
python 定时器,轮询定时器的实例
2019/02/20 Python
python 基于dlib库的人脸检测的实现
2019/11/08 Python
深度学习入门之Pytorch 数据增强的实现
2020/02/26 Python
Python基于QQ邮箱实现SSL发送
2020/04/26 Python
Python3如何使用tabulate打印数据
2020/09/25 Python
德国亚洲食品网上商店:asiafoodland.de
2019/12/28 全球购物
WEB控件及HTML服务端控件能否调用客户端方法?如果能,请解释如何调用?
2015/08/25 面试题
大学生简历中个人的自我评价
2013/10/06 职场文书
英文简历中的自荐信范文
2013/12/14 职场文书
运动会解说词50字
2014/01/18 职场文书
本科毕业生自荐信
2014/06/02 职场文书
工作疏忽、懈怠的检讨书
2014/09/11 职场文书
教师正风肃纪剖析材料
2014/10/20 职场文书
体育教师个人工作总结
2015/02/09 职场文书
从np.random.normal()到正态分布的拟合操作
2021/06/02 Python
Java实现多文件上传功能
2021/06/30 Java/Android
Golang MatrixOne使用介绍和汇编语法
2022/04/19 Golang