# 扩展行为
### 介绍
行为增加了类具有*私有特征*的能力,也称为行为。这些与[本机PHP特性](http://php.net/manual/en/language.oop5.traits.php)相似,但它们具有一些明显的优点:
1. 行为具有自己的构造函数。
2. 行为可以具有私有或受保护的方法。
3. 方法和属性名称可以安全地冲突。
4. 可以通过行为动态扩展类。
### [](https://octobercms.com/docs/services/behaviors#compare-traits)性状比较
在哪里可以使用如下所示的PHP特性:
~~~
class MyClass
{
use \October\Rain\UtilityFunctions;
use \October\Rain\DeferredBinding;
}
~~~
行为以类似的方式使用:
~~~
class MyClass extends \October\Rain\Extension\Extendable
{
public $implement = [
'October.Rain.UtilityFunctions',
'October.Rain.DeferredBinding',
];
}
~~~
您可以在其中定义如下特征:
~~~
trait UtilityFunctions
{
public function sayHello()
{
echo "Hello from " . get_class($this);
}
}
~~~
行为定义如下:
~~~
class UtilityFunctions extends \October\Rain\Extension\ExtensionBase
{
protected $parent;
public function __construct($parent)
{
$this->parent = $parent;
}
public function sayHello()
{
echo "Hello from " . get_class($this->parent);
}
}
~~~
扩展对象始终作为第一个参数传递给Behavior的构造函数。
总结一下:
* 扩展\\ October \\ Rain \\ Extension \\ ExtensionBase以将您的类声明为“行为”
* 想要实现该行为的类需要扩展\\ October \\ Rain \\ Extension \\ Extendable
> **注意**:请参阅[使用特征而不是基类](https://octobercms.com/docs/services/behaviors#using-traits)
### [](https://octobercms.com/docs/services/behaviors#constructor-extension)扩展构造函数
任何使用`Extendable`或的类都可以使用`ExtendableTrait`静态`extend`方法扩展其构造函数。该参数应传递一个闭包,该闭包将作为类构造函数的一部分被调用。
~~~
MyNamespace\Controller::extend(function($controller) {
//
});
~~~
#### 动态声明属性
可以通过调用`addDynamicProperty`并传递属性名称和值来在可扩展对象上声明属性。
~~~
Post::extend(function($model) {
$model->addDynamicProperty('tagsCache', null);
});
~~~
> **注意**:尝试通过常规方法(`$this->foo = 'bar';`)在实现**October \\ Rain \\ Extension \\ ExtendableTrait**的对象上设置未声明的属性将不起作用。它不会引发异常,但也不会自动声明该属性。`addDynamicProperty`必须调用才能在可扩展对象上设置先前未声明的属性。
#### 检索动态属性
可以使用从ExtendableTrait继承的getDynamicProperties函数检索动态创建的属性。
因此,检索所有动态属性将如下所示:
~~~
$model->getDynamicProperties();
~~~
这将返回一个关联数组\[key => value\],其中key为动态属性名称,value为属性值。
如果知道我们想要什么属性,我们可以简单地将键(属性名称)附加到函数中:
~~~
$model->getDynamicProperties()[$key];
~~~
#### 动态创建方法
通过调用`addDynamicMethod`并传递方法名称和可调用对象(例如),可以将方法创建为可扩展对象`Closure`。
~~~
Post::extend(function($model) {
$model->addDynamicProperty('tagsCache', null);
$model->addDynamicMethod('getTagsAttribute', function() use ($model) {
if ($this->tagsCache) {
return $this->tagsCache;
} else {
return $this->tagsCache = $model->tags()->lists('name');
}
});
});
~~~
#### 检查方法的存在
您可以在检查的方法是否存在`Extendable`使用类`methodExists`类似PHP -方法`method_exists()`的功能。这将检测通过`addDynamicMethod`调用添加的标准方法和动态方法。`methodExists`接受一个参数:方法名称的字符串以检查其存在。
~~~
Post::extend(function($model) {
$model->addDynamicMethod('getTagsAttribute', function () use ($model) {
return $this->tagsCache;
});
});
$post = new Post;
$post->methodExists('getTagsAttribute'); // true
$post->methodExists('missingMethod'); // false
~~~
#### 列出所有可用的方法
要检索`Extendable`类中所有可用方法的列表,可以使用该`getClassMethods`方法。此方法的操作类似于PHP`get_class_methods()`函数,因为它返回一个类中的可用方法数组,但是除了该类中已定义的方法外,它还将列出扩展或通过`addDynamicMethod`调用提供的任何方法。
~~~
Post::extend(function($model) {
$model->addDynamicMethod('getTagsAttribute', function () use ($model) {
return $this->tagsCache;
});
});
$post = new Post;
$methods = $post->getClassMethods();
/**
* $methods = [
* 0 => '__construct',
* 1 => 'extend',
* 2 => 'getTagsAttribute',
* ...
* ];
*/
~~~
#### 动态实施行为
这种扩展构造函数的独特能力允许动态地执行行为,例如:
~~~
/**
* Extend the RainLab.Users controller to include the RelationController behavior too
*/
RainLab\Users\Controllers\Users::extend(function($controller) {
// Implement the list controller behavior dynamically
$controller->implement[] = 'Backend.Behaviors.RelationController';
// Declare the relationConfig property dynamically for the RelationController behavior to use
$controller->addDynamicProperty('relationConfig', '$/myvendor/myplugin/controllers/users/config_relation.yaml');
});
~~~
### [](https://octobercms.com/docs/services/behaviors#usage-example)使用范例
#### 行为/扩展类
~~~
<?php namespace MyNamespace\Behaviors;
class FormController extends \October\Rain\Extension\ExtensionBase
{
/**
* @var Reference to the extended object.
*/
protected $controller;
/**
* Constructor
*/
public function __construct($controller)
{
$this->controller = $controller;
}
public function someMethod()
{
return "I come from the FormController Behavior!";
}
public function otherMethod()
{
return "You might not see me...";
}
}
~~~
#### 延伸课程
此类`Controller`将实现`FormController`行为,然后这些方法将可用于(混合)该类。我们将重写该`otherMethod`方法。
~~~
<?php namespace MyNamespace;
class Controller extends \October\Rain\Extension\Extendable
{
/**
* Implement the FormController behavior
*/
public $implement = [
'MyNamespace.Behaviors.FormController'
];
public function otherMethod()
{
return "I come from the main Controller!";
}
}
~~~
#### 使用扩展名
~~~
$controller = new MyNamespace\Controller;
// Prints: I come from the FormController Behavior!
echo $controller->someMethod();
// Prints: I come from the main Controller!
echo $controller->otherMethod();
// Prints: You might not see me...
echo $controller->asExtension('FormController')->otherMethod();
~~~
#### 检测利用的扩展
要检查对象是否已通过行为扩展,可以`isClassExtendedWith`在对象上使用方法。
~~~
$controller->isClassExtendedWith('Backend.Behaviors.RelationController');
~~~
下面是`UsersController`使用此方法动态扩展第三方插件的示例,以避免避免其他插件也扩展上述第三方插件。
~~~
UsersController::extend(function($controller) {
// Implement behavior if not already implemented
if (!$controller->isClassExtendedWith('Backend.Behaviors.RelationController')) {
$controller->implement[] = 'Backend.Behaviors.RelationController';
}
// Define property if not already defined
if (!isset($controller->relationConfig)) {
$controller->addDynamicProperty('relationConfig');
}
// Splice in configuration safely
$myConfigPath = '$/myvendor/myplugin/controllers/users/config_relation.yaml';
$controller->relationConfig = $controller->mergeConfig(
$controller->relationConfig,
$myConfigPath
);
}
~~~
### 软定义
如果不存在行为类(如特征),则将引发“*找不到类”*错误。在某些情况下,如果系统中存在某种行为,您可能希望抑制此错误,以便有条件地实施。您可以通过`@`在类名的开头放置一个符号来实现。
~~~
class User extends \October\Rain\Extension\Extendable
{
public $implement = ['@RainLab.Translate.Behaviors.TranslatableModel'];
}
~~~
如果类名`RainLab\Translate\Behaviors\TranslatableModel`不存在,则不会引发任何错误。这等效于以下代码:
~~~
class User extends \October\Rain\Extension\Extendable
{
public $implement = [];
public function __construct()
{
if (class_exists('RainLab\Translate\Behaviors\TranslatableModel')) {
$this->implement[] = 'RainLab.Translate.Behaviors.TranslatableModel';
}
parent::__construct();
}
}
~~~
### [](https://octobercms.com/docs/services/behaviors#using-traits)使用特征而不是基类
对于那些您可能不想扩展`ExtensionBase`或`Extendable`类的情况,可以改用traits。您的类必须按以下方式实现:
首先,让我们创建将充当行为的类,即。可以由其他类实现。
~~~
<?php namespace MyNamespace\Behaviours;
class WaveBehaviour
{
use \October\Rain\Extension\ExtensionTrait;
/**
* When using the Extensiontrait, your behaviour also has to implement this method
* @see \October\Rain\Extension\ExtensionBase
*/
public static function extend(callable $callback)
{
self::extensionExtendCallback($callback);
}
public function wave()
{
echo "*waves*<br>";
}
}
~~~
现在,让我们创建一个能够使用ExtendableTrait实现行为的类。
~~~
class AI
{
use \October\Rain\Extension\ExtendableTrait;
/**
* @var array Extensions implemented by this class.
*/
public $implement;
/**
* Constructor
*/
public function __construct()
{
$this->extendableConstruct();
}
public function __get($name)
{
return $this->extendableGet($name);
}
public function __set($name, $value)
{
$this->extendableSet($name, $value);
}
public function __call($name, $params)
{
return $this->extendableCall($name, $params);
}
public static function __callStatic($name, $params)
{
return self::extendableCallStatic($name, $params);
}
public static function extend(callable $callback)
{
self::extendableExtendCallback($callback);
}
public function youGotBrains()
{
echo "I've got an AI!<br>";
}
}
~~~
AI类现在可以使用行为。让我们对其进行扩展,并让该类实现WaveBehaviour。
~~~
<?php namespace MyNamespace\Classes;
class Robot extends AI
{
public $implement = [
'MyNamespace.Behaviours.WaveBehaviour'
];
public function identify()
{
echo "I'm a Robot<br>";
echo $this->youGotBrains();
echo $this->wave();
}
}
~~~
现在,您可以按以下方式使用机器人:
~~~
$robot = new Robot();
$robot->identify();
~~~
将输出:
~~~
I'm a Robot
I've got an AI!
*waves*
~~~
记得:
* 使用`ExtensionTrait`方法时,`ExtensionBase`应将from方法应用于类。
* 使用`ExtendableTrait`方法时,`Extendable`应将from方法应用于类。
- 基本说明
- 基本操作
- October cms 安装
- 后台控制器路径
- 图标
- 获取安装网上的插件/主题
- 插件构造器使用
- 定时任务
- October后台控制器
- vscode编辑器
- ajax操作
- 使用
- ajax更新组件
- ajax属性API
- JavaScript API
- ajax综合使用
- 主题
- 多语言主题
- 安装市场主题
- 主题程序处理
- 主题
- 页面
- 部件
- 布局
- 内容
- 组件
- 媒体
- 主题表单操作
- 表单使用
- 表单后端程序处理
- 插件
- 自定义插件
- 插件说明
- 插件导航条
- 插件数据库设置
- 插件的设置管理
- 插件的配置文件config
- 组件
- app服务
- app容器
- 扩展行为
- 缓存
- Collection类
- Lazy Collections
- Collection方法
- 助手函数
- 数组助手函数
- 路径助手函数
- 玄乐助手函数
- 其他助手函数
- 错误与记录
- 事件处理
- HTML页面
- 文件与目录操作
- 散列和加密
- 邮件
- 邮件内容
- 邮件发送
- 分页
- 模板解析器
- 动态解析器语法
- 队列消息
- 请求与输入
- 响应
- 视图
- 路由器
- 配置
- 验证操作
- 处理错误消息
- 错误消息与视图
- 可用的验证规则
- 有条件的验证规则
- 验证数组
- 错误消息
- 自定义验证规则
- 模型操作
- 定义模型与其属性
- 检索模型
- 插入与更新
- 删除模型
- 查询范围
- 事件操作
- 关联操作
- 定义关系
- 关系类型
- 多肽关系
- 关系查询
- 渴望加载
- 插入模型
- 数据库操作
- 基本用法
- 数据表结构
- 查询连贯操作
- 结果检索
- select子句
- 插入更新
- where子句
- 排序,分组,限制和偏移
- 文件附件
- Collection操作
- 属性操作
- 系列化json
- 数据库属性
- 数据库行为
- 控制器
- 后台控制器定义
- 后台页面
- 后台组件
- 后台表单
- 表单组件
- 表单视图
- 表单行为
- 后台列表
- 列表行为
- 列表过滤器
- 可用列类型
- 关系行为
- 关系行为类型
- 扩展关系行为
- 列表排序操作
- 导入导出操作
- 用于与权限
- corlate模板修改
- 修改顶部导航
- laravel问题
- 控制器不存在
- 控制器
- 路由组
- laravel笔记
- laravel 安装
- 伪静态配置
- 依赖注入 & 控制器
- 中间件
- 路由文件
- 视图