The objective of PHP traits is to manage a bunch of logic. However what is the best way to make this bunch of logic works according some dedicated properties and avoiding naming conflicts ?
I'm thinking about MVC and particularly the model class. Indeed models seems to be good candidates for traits. Models can implement tree structure, be draftable, revisionnable, sluggable, and so on.
I would like to write something like this:
class MyModel extends Model {
use Tree, Revision, Slug;
protected $_behaviors = array(
'Tree' => array('parentFieldname' => 'p_id'),
'Revision' => array(/* some options */),
'Slug' => array(/* some options */)
);
public function __construct() {
foreach($this->_behaviors as &$options) {
$options += /* trait defaults ? */
}
}
}
If I intend to set the Tree trait like this :
trait Tree {
protected $_defaults = array(
'parentFieldname' => 'parent_id',
/*...other options...*/
);
public function moveUp();
public function moveDown();
public function setParent(); //<- need the `'parentFieldname' => 'p_id'`attribute
/*...and so on...*/
}
I'll reach into naming conflicts because of $_defaults
since each trait needs its own defaults. Using the name of the trait as property name imply using something like (new ReflectionClass(__CLASS__))->getTraits())
... which is not really awesome.
In other words is there a way to create traits with "overridable defaults" and avoid naming conflicts ?
Like you will do in every OOP-concept: Open your eyes! Thats exactly the same, as you extends a class and misuse already existing property. Nothing more.
class A {
protected $defaults = array ('foo' => 'bar');
}
class B extends A {
protected $defaults = array('foo2' => 42); // Bum: 'foo' disappeared
}
Having a generic $_defaults
-property sounds to me like a code smell anyway: What "defaults"? This defaults? System defaults? Application defaults? [1] Setup your class with values, not "defaults", because thats (spreading default value) something for an initialization process, or the initialization of the concrete properties (public $parentFieldName = 'parent_id';
)
trait A {
public $parentFieldName = 'parent_id';
public function construct ($options) { /
if (isset($options['parentFieldName'])) {
$this->parentFieldName = $options['parentFieldName'];
}
}
}
class Foo {
use A {
A::construct as protected constructA;
}
public function __construct ($options) {
$this->constructA($options['A']);
}
}
Some notes: It's important, that you alias construct()
because it would conflict with other methods (from other traits) as well, and construct()
is not a special method. It's only named this way (from me) to clarify, that it is "a kind of" constructor. Other names like init()
or such would work as well of course ;)
You must call it within the "real" constructor (see Foo::__construct()
) yourself.
[1] "default" as an identifier is like "type", "status", "i", ...: They are to generic to be useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With