october / extension
Extension based classes, like private Traits
Requires
- php: >=5.5.9
- dev-master / 1.0.x-dev
- 1.0.x-dev
- v1.0.419
- v1.0.418
- v1.0.417
- v1.0.416
- v1.0.415
- v1.0.414
- v1.0.413
- v1.0.412
- v1.0.411
- v1.0.410
- v1.0.409
- v1.0.408
- v1.0.407
- v1.0.406
- v1.0.405
- v1.0.404
- v1.0.403
- v1.0.402
- v1.0.401
- v1.0.400
- v1.0.399
- v1.0.398
- v1.0.397
- v1.0.396
- v1.0.395
- v1.0.394
- v1.0.393
- v1.0.392
- v1.0.391
- v1.0.390
- v1.0.389
- v1.0.388
- v1.0.387
- v1.0.386
- v1.0.385
- v1.0.384
- v1.0.383
- v1.0.382
- v1.0.381
- v1.0.380
- v1.0.379
- v1.0.378
- v1.0.377
- v1.0.376
- v1.0.375
- v1.0.374
- v1.0.373
- v1.0.372
- v1.0.371
- v1.0.370
- v1.0.369
- v1.0.368
- v1.0.367
- v1.0.366
- v1.0.365
- v1.0.364
- v1.0.363
- v1.0.362
- v1.0.361
- v1.0.360
- v1.0.359
- v1.0.358
- v1.0.357
- v1.0.356
- v1.0.355
- v1.0.354
- v1.0.353
- v1.0.352
- v1.0.351
- v1.0.350
- v1.0.349
- v1.0.348
- v1.0.347
- v1.0.346
- v1.0.345
- v1.0.344
- v1.0.343
- v1.0.342
- v1.0.341
- v1.0.340
- v1.0.339
- v1.0.338
- v1.0.337
- v1.0.336
- v1.0.335
- v1.0.334
- v1.0.333
- v1.0.332
- v1.0.331
- v1.0.330
- v1.0.329
- v1.0.328
- v1.0.327
- v1.0.326
- v1.0.325
- v1.0.324
- v1.0.323
- v1.0.322
- v1.0.321
- v1.0.320
- v1.0.319
- dev-develop
- dev-l55upgrade
- dev-stable
- dev-halcyon
- dev-laravel5
This package is not auto-updated.
Last update: 2018-12-08 08:18:01 UTC
README
Adds the ability for classes to have private traits, also known as Behaviors. These are similar to native PHP Traits except they have some distinct benefits:
- Behaviors have their own constructor.
- Behaviors can have private or protected methods.
- Methods and property names can conflict safely.
- Class can be extended with behaviors dynamically.
Where you might use a trait like this:
class MyClass
{
use \October\Rain\UtilityFunctions;
use \October\Rain\DeferredBinding;
}
A behavior is used in a similar fashion:
class MyClass extends \October\Rain\Extension\Extendable
{
public $implement = [
'October.Rain.UtilityFunctions',
'October.Rain.DeferredBinding',
];
}
Where you might define a trait like this:
trait UtilityFunctions
{
public function sayHello()
{
echo "Hello from " . get_class($this);
}
}
A behavior is defined like 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);
}
}
The extended object is always passed as the first parameter to the Behavior's constructor.
Usage example
Behavior / Extension class
<?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...";
}
}
Extending a class
This Controller
class will implement the FormController
behavior and then the methods will become available (mixed in) to the class. We will override the otherMethod
method.
<?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!";
}
}
Using the extension
$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();
Dynamically using a behavior / Constructor extension
Any class that uses the Extendable
or ExtendableTrait
can have its constructor extended with the static extend()
method. The argument should pass a closure that will be called as part of the class constructor. For example:
/**
* Extend the Pizza Shop to include the Master Splinter behavior too
*/
MyNamespace\Controller::extend(function($controller){
// Implement the list controller behavior dynamically
$controller->implement[] = 'MyNamespace.Behaviors.ListController';
});
Dynamically creating methods
Methods can be added to a Model
through the use of addDynamicMethod
.
Post::extend(function($model) {
$model->addDynamicMethod('getTagsAttribute', function() use ($model) {
return $model->tags()->lists('name');
});
});
Soft definition
If a behavior class does not exist, like a trait, an Class not found error will be thrown. In some cases you may wish to suppress this error, for conditional implementation if a module is present in the system. You can do this by placing an @
symbol at the beginning of the class name.
class User extends \October\Rain\Extension\Extendable
{
public $implement = ['@RainLab.Translate.Behaviors.TranslatableModel'];
}
If the class name RainLab\Translate\Behaviors\TranslatableModel
does not exist, no error will be thrown. This is the equivalent of the following code:
class User extends \October\Rain\Extension\Extendable
{
public $implement = [];
public function __construct()
{
if (class_exists('RainLab\Translate\Behaviors\TranslatableModel')) {
$controller->implement[] = 'RainLab.Translate.Behaviors.TranslatableModel';
}
parent::__construct();
}
}
Using Traits instead of base classes
In some cases you may not wish to extend the ExtensionBase
or Extendable
classes, due to other needs. So you can use the traits instead, although obviously the behavior methods will not be available to the parent class.
-
When using the
ExtensionTrait
the methods fromExtensionBase
should be applied to the class. -
When using the
ExtendableTrait
the methods fromExtendable
should be applied to the class.