Object和Component的区别是什么

70次阅读
没有评论

共计 3893 个字符,预计需要花费 10 分钟才能阅读完成。

这篇文章给大家介绍 Object 和 Component 的区别是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

由于 Componet 引入了事件、行为,因此,它并非简单继承了 Object 的属性实现方式,而是基于同样的机制,重载了 __get() __set() 等函数。但从实现机制上来讲,是一样的。这个不影响理解。

前面说过,官方将 Yii 定位于一个基于组件的框架。可见组件这一概念是 Yii 的基础。如果你有兴趣阅读 Yii 的源代码或是 API 文档,你将会发现,Yii 几乎所有的核心类都派生于(继承自) yii\base\Component。

在 Yii1.1 时,就已经有了 component 了,那时是 CComponent。Yii2 将 Yii1.1 中的 CComponent 拆分成两个类:yii\base\Object 和 yii\base\Component。

其中,Object 比较轻量级些,通过 getter 和 setter 定义了类的属性 (property)。Component 派生自 Object,并支持事件(event) 和行为(behavior)。因此,Component 类具有三个重要的特性:属性(property)、事件(event)、行为(behavior)。

相信你或多或少了解过,这三个特性是丰富和拓展类功能、改变类行为的重要切入点。因此,Component 在 Yii 中的地位极高。

在提供更多功能、更多便利的同时,Component 由于增加了 event 和 behavior 这两个特性,在方便开发的同时,也牺牲了一定的效率。如果开发中不需要使用 event 和 behavior 这两个特性,比如表示一些数据的类。那么,可以不从 Component 继承,而从 Object 继承。典型的应用场景就是如果表示用户输入的一组数据,那么,使用 Object。而如果需要对对象的行为和能响应处理的事件进行处理,毫无疑问应当采用 Component。从效率来讲,Object 更接近原生的 PHP 类,因此,在可能的情况下,应当优先使用 Object。

Object 的配置方法

Yii 提供了一个统一的配置对象的方式。这一方式贯穿整个 Yii。Application 对象的配置就是这种配置方式的体现:

$config = yii\helpers\ArrayHelper::merge(

require(__DIR__ . /../../common/config/main.php),

require(__DIR__ . /../../common/config/main-local.php),

require(__DIR__ . /../config/main.php),

require(__DIR__ . /../config/main-local.php)

);

$application = new yii\web\Application($config);

$config 看着复杂,但本质上就是一个各种配置项的数组。Yii 中就是统一使用数组的方式对对象进行配置,而实现这一切的关键就在 yii\base\Object 定义的构造函数中:

public function __construct($config = [])

{

if (!empty($config)) {

Yii::configure($this, $config);

}

$this- init();

}

所有 yii\base\Object 的构建流程是:

构建函数以 $config 数组为参数被自动调用。

构建函数调用 Yii::configure() 对对象进行配置。

在最后,构造函数调用对象的 init() 方法进行初始化。

数组配置对象的秘密在 Yii::configure() 中,但说破了其实也没有什么神奇的:

public static function configure($object, $properties)

{

foreach ($properties as $name = $value) {

$object- $name = $value;

}

return $object;

}

配置的过程就是遍历 $config 配置数组,将数组的键作为属性名,以对应的数组元素的值对对象的属性赋值。因此,实现 Yii 这一统一的配置方式的要点有:

继承自 yii\base\Object。

为对象属性提供 setter 方法,以正确处理配置过程。

如果需要重载构造函数,请将 $config 作为该构造函数的最后一个参数,并将该参数传递给父构造函数。

重载的构造函数的最后,一定记得调用父构造函数。

如果重载了 yii\base\Object::init() 函数,注意一定要在重载函数的开头调用父类的 init()。

只要实现了以上要点,就可以使得你编写的类可以按照 Yii 约定俗成的方式进行配置。这在编写代码的过程中,带来许多便利。

像你这么聪明的,肯定会提出来,如果配置数组的某个配置项,也是一个数组,这怎么办? 如果某个对象的属性,也是一个对象,而非一个简单的数值或字符串时,又怎么办?

这两个问题,其实是同质的。如果一个对象的属性,是另一个对象,就像 Application 里会引入诸多的 Component 一样,这是很常见的。如后面会看到的 $app- request 中的 request 属性就是一个对象。那么,在配置 $app 时,必然要配置到这个 reqeust 对象。既然 request 也是一个对象,那么他的配置要是按照 Yii 的规矩来,也就是用一个数组来配置它。因此,上面提到的这两个问题,其实是同质的。

那么,怎么实现呢? 秘密在于 setter 函数。由于 $app 在进行配置时,最终会调用 Yii::configure() 函数。该函数又不区分配置项是简单的数值还是数组,就直接使用 $object- $name = $value 完成属性的赋值。那么,对于对象属性,其配置值 $value 是一个数组,为了使其正确配置。你需要在其 setter 函数上做出正确的处理方式。Yii 应用 yii\web\Application 就是依靠定义专门的 setter 函数,实现自动处理配置项的。比如,我们在 Yii 的配置文件中,可以看到一个配置项 components,一般情况下,他的内容是这样的:

components = [

request = [

// !!! insert a secret key in the following (if it is empty) –

// this is required by cookie validation

cookieValidationKey = v7mBbyetv4ls7t8UIqQ2IBO60jY_wf_U ,

],

user = [

identityClass = common\models\User ,

enableAutoLogin = true,

],

log = [

traceLevel = YII_DEBUG ? 3 : 0,

targets = [

[

class = yii\log\FileTarget ,

levels = [error , warning],

],

],

],

errorHandler = [

errorAction = site/error ,

],

],

这是一个典型嵌套配置数组。那么 Yii 是如何把他们配置好的呢? 聪明的你肯定想到了,Yii 一定是定义了一个名为 setComponents 的 setter 函数。当然,Yii 并未将该函数放在 yii\web\Application 里,而是放在父类 yii\di\ServiceLocator 里面。至于 ServiceLocator 是何方神圣,在后面 服务定位器(Service Locator) 部分会讲到,这里你只需要知道它是 Application 的父类,提供 components 属性的 setter 方法就可以了:

public function setComponents($components)

{

foreach ($components as $id = $component) {

$this- set($id, $component);

}

}

这里有个成员函数,$this- set(),他是服务定位器用来注册服务的方法。我们暂时不讲这个东西,留待 服务定位器(Service Locator) 部分再讲。现在只要知道这个函数把配置文件中的 components 配置项搞定就可以了。

从 yii\base\Object::__construct() 来看,对于所有 Object,包括 Component 的属性,都经历这么 4 个阶段:

预初始化阶段。这是最开始的阶段,就是在构造函数 __construct() 的开头可以设置 property 的默认值。

对象配置阶段。也就是前面提到构造函数调用 Yii::configure($this, $config) 阶段。这一阶段可以覆盖前一阶段设置的 property 的默认值,并补充没有默认值的参数,也就是必备参数。$config 通常由外部代码传入或者通过配置文件传入。

后初始化阶段。也就是构造函数调用 init() 成员函数。通过在 init() 写入代码,可以对配置阶段设置的值进行检查,并规范类的 property。

类方法调用阶段。前面三个阶段是不可分的,由类的构造函数一口气调用的。也就是说一个类一但实例化,那么就至少经历了前三个阶段。此时,该对象的状态是确定且可靠的,不存在不确定的 property。所有的属性要么是默认值,要么是传入的配置值,如果传入的配置有误或者冲突,那么也经过了检查和规范。也就是说,你就放心用吧。

关于 Object 和 Component 的区别是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-03发表,共计3893字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)