Alexander Makarov
13 years ago
6 changed files with 290 additions and 3 deletions
@ -0,0 +1,44 @@ |
|||||||
|
Base classes and interfaces |
||||||
|
=========================== |
||||||
|
|
||||||
|
Object |
||||||
|
------ |
||||||
|
|
||||||
|
Object is the base class for many other Yii2 classes. |
||||||
|
|
||||||
|
### property feature |
||||||
|
|
||||||
|
#### Why |
||||||
|
|
||||||
|
To be able to make property `public` initially and then seamlessly make it |
||||||
|
`private` or `protected` by adding getter and setter method. That will *not* |
||||||
|
change API. Results in less repetitive code. Performance drop isn't significant. |
||||||
|
|
||||||
|
### callbacks and expressions |
||||||
|
|
||||||
|
### [[Object::create()]|create] method |
||||||
|
|
||||||
|
This method is a powerful way to instantiate a class. Differences from `new`: |
||||||
|
|
||||||
|
- Calls class constructor (same the `new` operator); |
||||||
|
- Initializes the object properties using the name-value pairs given as the |
||||||
|
last parameter to this method; |
||||||
|
- Calls [[Initable::init|init]] if the class implements [[Initable]]. |
||||||
|
|
||||||
|
#### Why |
||||||
|
|
||||||
|
To support class dependencies and their lazy loading. |
||||||
|
|
||||||
|
### [[Initable]] interface |
||||||
|
|
||||||
|
Developer will implement initable interface if running `init()` needed and will |
||||||
|
skip it if not. |
||||||
|
|
||||||
|
#### Why |
||||||
|
|
||||||
|
Indicates where `init()` will be called and where not. More explicit than it was |
||||||
|
in Yii 1. |
||||||
|
|
||||||
|
Component |
||||||
|
--------- |
||||||
|
|
@ -0,0 +1,13 @@ |
|||||||
|
Git branches and tags |
||||||
|
===================== |
||||||
|
|
||||||
|
Tags |
||||||
|
---- |
||||||
|
|
||||||
|
Each release should be tagged with v2.X.X and message "Yii 2.X.X release". |
||||||
|
|
||||||
|
Branches |
||||||
|
-------- |
||||||
|
|
||||||
|
What should be in master branch? |
||||||
|
Do we need another branches? |
@ -0,0 +1,171 @@ |
|||||||
|
Alex's Code Review, 2011.11.12 |
||||||
|
============================== |
||||||
|
|
||||||
|
Overall hierarchy |
||||||
|
------------------ |
||||||
|
|
||||||
|
Generally is OK. Like that `Object` and `Component` are now separated. |
||||||
|
I've generated 2 diagrams under `docs/` to see it better as a whole. |
||||||
|
|
||||||
|
Object |
||||||
|
------ |
||||||
|
|
||||||
|
### property feature |
||||||
|
|
||||||
|
Why returning anything when setting a value? |
||||||
|
|
||||||
|
~~~ |
||||||
|
if (method_exists($this, $setter)) { |
||||||
|
// ??? |
||||||
|
return $this->$setter($value); |
||||||
|
} |
||||||
|
~~~ |
||||||
|
|
||||||
|
Is it OK that `canGetProperty` and `canSetProperty` will return `false` for real |
||||||
|
class members? |
||||||
|
|
||||||
|
### callbacks and expressions |
||||||
|
|
||||||
|
We're using 5.3. What's the reason to support `eval()` in `evaluateExpression` if |
||||||
|
we have anonymous functions? Is that for storing code as string inside of DB (RBAC)? |
||||||
|
|
||||||
|
If we're going to get rid of `eval()`, cosider remaning method to something about callback. |
||||||
|
If not then we definitely need to use anonymous functions in API docs and the guide |
||||||
|
where possible. |
||||||
|
|
||||||
|
### Object::create() |
||||||
|
|
||||||
|
#### `__construct` issue |
||||||
|
|
||||||
|
Often a class doesn't have `__construct` implementation and `stdClass` doesn't have |
||||||
|
default one either but Object::create() always expects constructor to be |
||||||
|
defined. See `ObjectTest`. Either `method_exists` call or `Object::__construct` needed. |
||||||
|
|
||||||
|
#### How to support object factory like we do with CWidgetFactory? |
||||||
|
|
||||||
|
~~~ |
||||||
|
class ObjectConfig |
||||||
|
{ |
||||||
|
public function configure($class) |
||||||
|
{ |
||||||
|
$config = $this->load($class); |
||||||
|
// apply config to $class |
||||||
|
} |
||||||
|
|
||||||
|
private function load($class) |
||||||
|
{ |
||||||
|
// get class properties from a config file |
||||||
|
// in this method we need to walk all the |
||||||
|
// inheritance hierarchy down to Object itself |
||||||
|
return array( |
||||||
|
'property' => 'value', |
||||||
|
// … |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
~~~ |
||||||
|
|
||||||
|
Then we need to add `__construct` to `Object` (or implement `Initalbe`): |
||||||
|
|
||||||
|
~~~ |
||||||
|
class Object |
||||||
|
{ |
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$conf = new ObjectConfig(); |
||||||
|
$conf->configure($this); |
||||||
|
} |
||||||
|
} |
||||||
|
~~~ |
||||||
|
|
||||||
|
This way we'll be able to set defaults for any object. |
||||||
|
|
||||||
|
#### Do we need to support lazy class injection? |
||||||
|
|
||||||
|
Currently there's no way to lazy-inject class into another class property via |
||||||
|
config. Do we need it? If yes then we can probably extend component config to support |
||||||
|
the following: |
||||||
|
|
||||||
|
~~~ |
||||||
|
class Foo extends Object |
||||||
|
{ |
||||||
|
public $prop; |
||||||
|
} |
||||||
|
|
||||||
|
class Bar extends Object |
||||||
|
{ |
||||||
|
public $prop; |
||||||
|
} |
||||||
|
|
||||||
|
$config = array( |
||||||
|
'prop' => array( |
||||||
|
'class' => 'Bar', |
||||||
|
'prop' => 'Hello!', |
||||||
|
), |
||||||
|
); |
||||||
|
|
||||||
|
$foo = Foo::create($config); |
||||||
|
echo $foo->bar->prop; |
||||||
|
// will output Hello! |
||||||
|
~~~ |
||||||
|
|
||||||
|
Should it support infinite nesting level? |
||||||
|
|
||||||
|
### Why `Event` is `Object`? |
||||||
|
|
||||||
|
There's no need to extend from `Object`. Is there a plan to use `Object` features |
||||||
|
later? |
||||||
|
|
||||||
|
Initable |
||||||
|
-------- |
||||||
|
|
||||||
|
Interface itself looks OK. Its usage is OK too. |
||||||
|
|
||||||
|
`Initable::preinit` mentioned in `Yii::create()` docs but neither defined in |
||||||
|
the interface nor called in the code. |
||||||
|
|
||||||
|
Behaviors |
||||||
|
--------- |
||||||
|
|
||||||
|
Overall I wasn't able to use behaviors. See `BehaviorTest`. |
||||||
|
|
||||||
|
### Wrong API docs at Behavior |
||||||
|
|
||||||
|
Docs mention properties and events but not methods. |
||||||
|
|
||||||
|
### Should behaviors be able to define events for owner components? |
||||||
|
|
||||||
|
Why not? Should be a very good feature in order to make behaviors customizable. |
||||||
|
|
||||||
|
### Multiple behaviors can be attached to the same component |
||||||
|
|
||||||
|
What if we'll have multiple methods / properties / events with the same name? |
||||||
|
|
||||||
|
### How to use Behavior::attach? |
||||||
|
|
||||||
|
Looks like it is used by `Component::attachBehavior` but can't be used without it. |
||||||
|
Why it's public then? Can we move it to `Component?` |
||||||
|
|
||||||
|
Events |
||||||
|
------ |
||||||
|
|
||||||
|
Class itself looks OK. Component part is OK as well but I've not tested |
||||||
|
it carefully. Overall it seems concept is the same as in Yii1. |
||||||
|
|
||||||
|
### Event declaration: the on-method is mostly repetitive for every event. Should we choose a different way of declaring events? |
||||||
|
|
||||||
|
Maybe. People complained previously about too many code for event declaration. |
||||||
|
|
||||||
|
### Should we implement some additional event mechanism, such as global events? |
||||||
|
|
||||||
|
Why use two different implementations in a single application? |
||||||
|
|
||||||
|
Exceptions |
||||||
|
---------- |
||||||
|
|
||||||
|
- Should we convert all errors, warnings and notices to exceptions? |
||||||
|
|
||||||
|
Coding style |
||||||
|
------------ |
||||||
|
|
||||||
|
See `docs/code_style.md`. |
@ -0,0 +1,32 @@ |
|||||||
|
<?php |
||||||
|
class BarClass extends \yii\base\Component |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
class BarBehavior extends \yii\base\Behavior |
||||||
|
{ |
||||||
|
public $behaviorProperty = 'behavior property'; |
||||||
|
|
||||||
|
public function behaviorMethod() |
||||||
|
{ |
||||||
|
return 'behavior method'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* BehaviorTest |
||||||
|
*/ |
||||||
|
class BehaviorTest extends \yii\test\TestCase |
||||||
|
{ |
||||||
|
public function testAttachAndAccessing() |
||||||
|
{ |
||||||
|
$bar = BarClass::create(); |
||||||
|
$behavior = new BarBehavior(); |
||||||
|
$bar->attachBehavior('bar', $bar); |
||||||
|
$this->assertEquals('behavior property', $bar->behaviorProperty); |
||||||
|
$this->assertEquals('behavior method', $bar->behaviorMethod); |
||||||
|
$this->assertEquals('behavior property', $bar->bar->behaviorProperty); |
||||||
|
$this->assertEquals('behavior method', $bar->bar->behaviorMethod); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
<?php |
||||||
|
class Foo extends \yii\base\Object |
||||||
|
{ |
||||||
|
public $prop; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* ObjectTest |
||||||
|
*/ |
||||||
|
class ObjectTest extends \yii\test\TestCase |
||||||
|
{ |
||||||
|
public function testCreate() |
||||||
|
{ |
||||||
|
$foo = Foo::create(array( |
||||||
|
'prop' => array( |
||||||
|
'test' => 'test', |
||||||
|
), |
||||||
|
)); |
||||||
|
|
||||||
|
$this->assertEquals('test', $foo->prop['test']); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue