# 擴展行為
### 介紹
行為增加了類具有*私有特征*的能力,也稱為行為。這些與[本機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 安裝
- 偽靜態配置
- 依賴注入 & 控制器
- 中間件
- 路由文件
- 視圖