行为使类能够拥有私有特性,这些特性与 原生 PHP 特性 相似,但它们具有一些独特的优点。
你可能会像这样使用 PHP trait 的地方。
class MyClass
{
use \October\Rain\UtilityFunctions;
use \October\Rain\DeferredBinding;
}一个行为以类似的方式使用。
class MyClass extends \October\Rain\Extension\Extendable
{
public $implement = [
\October\Rain\UtilityFunctions::class,
\October\Rain\DeferredBinding::class,
];
}你可能会像这样定义一个特性。
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);
}
}扩展对象总是作为第一个参数传递给构造函数。总之,使用行为时请扩展以下类。
October\Rain\Extension\ExtensionBase 以将类声明为行为。October\Rain\Extension\Extendable 作为实现该行为的类。任何继承自 Extendable 类的类,都可以通过静态 extend 方法扩展其构造函数。该参数应传入一个闭包,该闭包将作为类构造函数的一部分被调用。
MyClass::extend(function($controller) {
//
});如果行为类不存在,例如 trait,将抛出类未找到错误。在某些情况下,您可能希望抑制此错误,以便在系统中存在某个行为时进行条件实现。您可以通过在类名前面放置一个 @ 符号来实现。
在以下示例中,如果类名 RainLab\Translate\Behaviors\TranslatableModel 不存在,将不会抛出任何错误。
class User extends \October\Rain\Extension\Extendable
{
public $implement = [
'@'.\RainLab\Translate\Behaviors\TranslatableModel::class
];
}这种扩展构造函数的独特能力允许动态实现行为,例如,使用 implementClassWith 方法在 UsersController 类中实现 RelationController 类。
UsersController::extend(function($controller) {
$controller->implementClassWith(\Backend\Behaviors\RelationController::class);
});
implementClassWith方法可以安全地多次调用,它会检查类是否已经实现了该行为并实现它。
使用 extendClassWith 方法在对象构建后扩展它。以下示例将动态地扩展一个 Model 类,使用存储在数据库中的类名。
public function afterFetch()
{
$this->extendClassWith($this->class_type);
}要检查对象是否已通过某个行为进行扩展,您可以使用对象上的 isClassExtendedWith 方法。
$controller->isClassExtendedWith(\Backend\Behaviors\RelationController::class);为了专门调用某个行为中的方法,请使用 asExtension 方法,该方法接受类的基本名称或完全限定类作为其参数。
echo $controller->asExtension('RelationController')->otherMethod();可以将方法添加到可扩展对象上,通过调用 addDynamicMethod 并传入方法名和一个可调用对象,例如一个 Closure。
MyModel::extend(function($model) {
$model->addDynamicMethod('getTagsAttribute', function() use ($model) {
return '...';
});
});要检查 Extendable 类中某个方法是否存在,请调用 methodExists 方法 - 类似于 PHP 的 method_exists() 函数。这将检测到标准方法、行为中的方法以及通过 addDynamicMethod 调用添加的动态方法。
$post = new Post;
$post->methodExists('getTagsAttribute'); // true
$post->methodExists('missingMethod'); // false要获取 Extendable 类中所有可用方法的列表,你可以使用 getClassMethods 方法。此方法的操作类似于 PHP 的 get_class_methods() 函数,因为它会返回一个类中可用方法的数组,但除了类中定义的方法外,它还会列出由扩展或通过 addDynamicMethod 调用提供的任何方法。
$post = new Post;
$methods = $post->getClassMethods();
/**
* $methods = [
* 0 => '__construct',
* 1 => 'extend',
* 2 => 'getTagsAttribute',
* ...
* ];
*/namespace MyNamespace\Behaviors;
class FormController extends \October\Rain\Extension\ExtensionBase
{
/**
* @var Controller controller is a reference to the extended object.
*/
protected $controller;
/**
* __construct
*/
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::class
];
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();