diff --git a/framework/YiiBase.php b/framework/YiiBase.php index 4c370fa..0f58671 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -290,9 +290,9 @@ class YiiBase * the class. For example, * * ~~~ - * $component = Yii::createComponent('@app/components/GoogleMap'); - * $component = Yii::createComponent('\application\components\GoogleMap'); - * $component = Yii::createComponent(array( + * $component = Yii::create('@app/components/GoogleMap'); + * $component = Yii::create('\application\components\GoogleMap'); + * $component = Yii::create(array( * 'class' => '@app/components/GoogleMap', * 'apiKey' => 'xyz', * )); @@ -310,7 +310,7 @@ class YiiBase * @return mixed the created object * @throws \yii\base\Exception if the configuration is invalid. */ - public static function createComponent($config) + public static function create($config) { if (is_string($config)) { $class = $config; diff --git a/framework/base/Behavior.php b/framework/base/Behavior.php index 1400beb..3e9ca0a 100644 --- a/framework/base/Behavior.php +++ b/framework/base/Behavior.php @@ -19,7 +19,7 @@ namespace yii\base; * @author Qiang Xue * @since 2.0 */ -class Behavior extends Component +class Behavior extends Object { private $_owner; diff --git a/framework/base/Component.php b/framework/base/Component.php index 8589e7d..2159a63 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -10,44 +10,14 @@ namespace yii\base; /** - * Component is the base class for all components in Yii. - * - * Component implements the basis for *properties*, *events* and *behaviors*. - * - * A property is defined by a getter method (e.g. `getLabel`), - * and/or a setter method (e.g. `setLabel`). For example, the following - * getter and setter methods define a property named `label`: - * - * ~~~ - * private $_label; - * - * public function getLabel() - * { - * return $this->_label; - * } - * - * public function setLabel($value) - * { - * $this->_label = $value; - * } - * ~~~ - * - * A property can be accessed like a member variable of an object. - * Reading or writing a property will cause the invocation of the corresponding - * getter or setter method. For example, - * - * ~~~ - * // equivalent to $label = $component->getLabel(); - * $label = $component->label; - * // equivalent to $component->setLabel('abc'); - * $component->label = 'abc'; - * ~~~ + * Component is the base class for all component classes in Yii. * + * Extending from [[Object]], Component implements the *event* and *behavior* + * features in addition to the *property* feature. * * An event is defined by the presence of a method whose name starts with `on`. - * The event name is the method name. When an event is raised, functions - * (called *event handlers*) attached to the event will be invoked automatically. - * The `on` method is typically declared like the following: + * The event name is the method name. For example, the following method defines + * the `onClick` event: * * ~~~ * public function onClick($event) @@ -56,53 +26,52 @@ namespace yii\base; * } * ~~~ * - * An event can be raised by calling the [[raiseEvent]] method, upon which - * the attached event handlers will be invoked automatically in the order they - * are attached to the event. In the above example, if we call the `onClick` method, - * an `onClick` event will be raised. + * Event names are case-insensitive. * - * An event handler should be defined with the following signature: + * An event can be attached with one or multiple PHP callbacks, called *event handlers*. + * One can call [[raiseEvent]] to raise an event. When an event is raised, the attached + * event handlers will be invoked automatically in the order they are attached to the event. * - * ~~~ - * public function foo($event) { ... } - * ~~~ + * To attach an event handler to an event, call [[attachEventHandler]]. Alternatively, + * you can use the assignment syntax: `$component->onClick = $callback;`, + * where `$callback` refers to a valid PHP callback, which can be one of the followings: * - * where `$event` is an [[Event]] object which includes parameters associated with the event. - * - * To attach an event handler to an event, call [[attachEventHandler]]. - * Alternatively, you can also do the following: + * - global function: `'handleOnClick'` + * - object method: `array($object, 'handleOnClick')` + * - static method: `array('Page', 'handleOnClick')` + * - anonymous function: `function($event) { ... }` * + * The signature of an event handler should be like the following: * ~~~ - * $component->onClick = $callback; - * // or $component->onClick->add($callback); + * function foo($event) * ~~~ * - * where `$callback` refers to a valid PHP callback. Some examples of `$callback` are: + * where `$event` is an [[Event]] object which includes parameters associated with the event. + * + * Because `$component->onClick` is returned as a [[Vector]] with each item in the vector being + * an attached event handler, one can manipulate this [[Vector]] object to attach/detach event + * handlers, or adjust their relative orders. For example, * * ~~~ - * 'handleOnClick' // handleOnClick() is a global function - * array($object, 'handleOnClick') // $object->handleOnClick() - * array('Page', 'handleOnClick') // Page::handleOnClick() - * function($event) { ... } // anonymous function + * $component->onClick->insertAt(0, $callback); // attach a handler as the first one + * $component->onClick[] = $callback; // attach a handler as the last one + * unset($component->onClick[0]); // detach the first handler * ~~~ * - * Both property names and event names are *case-insensitive*. * * A behavior is an instance of [[Behavior]] or its child class. When a behavior is * attached to a component, its public properties and methods can be accessed via the - * component directly, as if the component owns those properties and methods. For example, + * component directly, as if the component owns those properties and methods. * * Multiple behaviors can be attached to the same component. * - * To attach a behavior to a component, call [[attachBehavior]]; and to detach the behavior + * To attach a behavior to a component, call [[attachBehavior]]; to detach a behavior * from the component, call [[detachBehavior]]. * - * Components created via [[\Yii::createComponent]] have life cycles. In particular, - * * @author Qiang Xue * @since 2.0 */ -class Component +class Component extends Object { private $_e; private $_b; @@ -129,18 +98,15 @@ class Component $getter = 'get' . $name; if (method_exists($this, $getter)) { // read property, e.g. getName() return $this->$getter(); - } - elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event, e.g. onClick() + } elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event, e.g. onClick() $name = strtolower($name); if (!isset($this->_e[$name])) { $this->_e[$name] = new Vector; } return $this->_e[$name]; - } - elseif (isset($this->_b[$name])) { // behavior + } elseif (isset($this->_b[$name])) { // behavior return $this->_b[$name]; - } - elseif (is_array($this->_b)) { // a behavior property + } elseif (is_array($this->_b)) { // a behavior property foreach ($this->_b as $object) { if (property_exists($object, $name) || $object->canGetProperty($name)) { return $object->$name; @@ -151,7 +117,7 @@ class Component } /** - * Sets value of a component property. + * Sets the value of a component property. * This method will check in the following order and act accordingly: * * - a property defined by a setter: set the property value @@ -170,15 +136,13 @@ class Component $setter = 'set' . $name; if (method_exists($this, $setter)) { // write property return $this->$setter($value); - } - elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event + } elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event $name = strtolower($name); if (!isset($this->_e[$name])) { $this->_e[$name] = new Vector; } return $this->_e[$name]->add($value); - } - elseif (is_array($this->_b)) { // behavior + } elseif (is_array($this->_b)) { // behavior foreach ($this->_b as $object) { if (property_exists($object, $name) || $object->canSetProperty($name)) { return $object->$name = $value; @@ -187,8 +151,7 @@ class Component } if (method_exists($this, 'get' . $name)) { throw new Exception('Setting read-only property: ' . get_class($this) . '.' . $name); - } - else { + } else { throw new Exception('Setting unknown property: ' . get_class($this) . '.' . $name); } } @@ -211,15 +174,12 @@ class Component $getter = 'get' . $name; if (method_exists($this, $getter)) { // property is not null return $this->$getter() !== null; - } - elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // has event handler + } elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // has event handler $name = strtolower($name); return isset($this->_e[$name]) && $this->_e[$name]->getCount(); - } - elseif (isset($this->_b[$name])) { // has behavior + } elseif (isset($this->_b[$name])) { // has behavior return true; - } - elseif (is_array($this->_b)) { + } elseif (is_array($this->_b)) { foreach ($this->_b as $object) { if (property_exists($object, $name) || $object->canGetProperty($name)) { return $object->$name !== null; @@ -247,24 +207,19 @@ class Component $setter = 'set' . $name; if (method_exists($this, $setter)) { // write property $this->$setter(null); - } - elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event + } elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event unset($this->_e[strtolower($name)]); - } - elseif (isset($this->_b[$name])) { // behavior + } elseif (isset($this->_b[$name])) { // behavior $this->detachBehavior($name); - } - elseif (is_array($this->_b)) { // behavior property + } elseif (is_array($this->_b)) { // behavior property foreach ($this->_b as $object) { if (property_exists($object, $name)) { return $object->$name = null; - } - elseif ($object->canSetProperty($name)) { + } elseif ($object->canSetProperty($name)) { return $object->$setter(null); } } - } - elseif (method_exists($this, 'get' . $name)) { + } elseif (method_exists($this, 'get' . $name)) { throw new Exception('Unsetting read-only property: ' . get_class($this) . '.' . $name); } } @@ -304,101 +259,6 @@ class Component } /** - * Creates a new component instance. - * - * This method differs from the PHP `new` operator in that it does the following - * steps to create a new component instance: - * - * - Call class constructor (same the `new` operator); - * - Initialize the component properties using the name-value pairs given as the - * last parameter to this method; - * - Call [[Initable::init|init]] if the class implements [[Initable]]. - * - * Parameters passed to this method will be used as the parameters to the object - * constructor. If, however, the last parameter is an array and the count of the parameters - * is one more than the count of declared constructor parameters, that parameter - * will be treated as name-value pairs for initializing the component properties. - * For example, - * - * ~~~ - * class Foo extends \yii\base\Component { - * public $c; - * public function __construct($a, $b) { ... } - * } - * - * $model = Foo::create(1, 2, array('c' => 3)); - * // which is equivalent to the following lines: - * $model = new Foo(1, 2); - * $model->c = 3; - * $model->init(); - * ~~~ - * - * @return object the created component - * @throws Exception if the configuration is invalid. - */ - public static function create() - { - $class = '\\' . get_called_class(); - if (($n = func_num_args()) > 0) { - $args = func_get_args(); - if (is_array($args[$n-1])) { - // the last parameter could be configuration array - $method = new \ReflectionMethod($class, '__construct'); - if ($method->getNumberOfParameters()+1 == $n) { - $config = $args[$n-1]; - array_pop($args); - } - } - $config['class'] = $class; - array_unshift($args, $config); - return call_user_func_array('\Yii::createComponent', $args); - } - else { - return \Yii::createComponent($class); - } - } - - /** - * Returns a value indicating whether a property is defined. - * A property is defined if there is a getter or setter method - * defined in the class. Note, property names are case-insensitive. - * @param string $name the property name - * @return boolean whether the property is defined - * @see canGetProperty - * @see canSetProperty - */ - public function hasProperty($name) - { - return $this->canGetProperty($name) || $this->canSetProperty($name); - } - - /** - * Returns a value indicating whether a property can be read. - * A property can be read if the class has a getter method - * for the property name. Note, property name is case-insensitive. - * @param string $name the property name - * @return boolean whether the property can be read - * @see canSetProperty - */ - public function canGetProperty($name) - { - return method_exists($this, 'get' . $name); - } - - /** - * Returns a value indicating whether a property can be set. - * A property can be written if the class has a setter method - * for the property name. Note, property name is case-insensitive. - * @param string $name the property name - * @return boolean whether the property can be written - * @see canGetProperty - */ - public function canSetProperty($name) - { - return method_exists($this, 'set' . $name); - } - - /** * Returns a value indicating whether an event is defined. * An event is defined if the class has a method whose name starts with `on` (e.g. `onClick`). * Note that event name is case-insensitive. @@ -509,26 +369,23 @@ class Component $name = strtolower($name); if ($event instanceof Event) { $event->name = $name; + $event->handled = false; } if (isset($this->_e[$name])) { foreach ($this->_e[$name] as $handler) { if (is_string($handler) || $handler instanceof \Closure) { call_user_func($handler, $event); - } - elseif (is_callable($handler, true)) { + } elseif (is_callable($handler, true)) { // an array: 0 - object, 1 - method name list($object, $method) = $handler; if (is_string($object)) { // static method call call_user_func($handler, $event); - } - elseif (method_exists($object, $method)) { + } elseif (method_exists($object, $method)) { $object->$method($event); - } - else { + } else { throw new Exception('Event "' . get_class($this) . '.' . $name . '" is attached with an invalid handler.'); } - } - else { + } else { throw new Exception('Event "' . get_class($this) . '.' . $name . '" is attached with an invalid handler.'); } @@ -537,9 +394,8 @@ class Component return; } } - } - elseif (!$this->hasEvent($name)) { - throw new Exception('Undefined event: ' . get_class($this) . '.' . $name); + } elseif (!$this->hasEvent($name)) { + throw new Exception('Raising unknown event: ' . get_class($this) . '.' . $name); } } @@ -566,14 +422,14 @@ class Component * - a string specifying the behavior class * - an object configuration array * - * parameter to [[\Yii::createComponent]] to create the behavior object. + * parameter to [[\Yii::create]] to create the behavior object. * @return Behavior the behavior object * @see detachBehavior */ public function attachBehavior($name, $behavior) { if (!($behavior instanceof Behavior)) { - $behavior = \Yii::createComponent($behavior); + $behavior = \Yii::create($behavior); } $behavior->attach($this); return $this->_b[$name] = $behavior; @@ -622,39 +478,4 @@ class Component $this->_b = null; } } - - /** - * Evaluates a PHP expression or callback under the context of this component. - * - * Valid PHP callback can be class method name in the form of - * array(ClassName/Object, MethodName), or anonymous function. - * - * If a PHP callback is used, the corresponding function/method signature should be - * - * ~~~ - * function foo($param1, $param2, ..., $component) { ... } - * ~~~ - * - * where the array elements in the second parameter to this method will be passed - * to the callback as `$param1`, `$param2`, ...; and the last parameter will be the component itself. - * - * If a PHP expression is used, the second parameter will be "extracted" into PHP variables - * that can be directly accessed in the expression. See [PHP extract](http://us.php.net/manual/en/function.extract.php) - * for more details. In the expression, the component object can be accessed using `$this`. - * - * @param mixed $_expression_ a PHP expression or PHP callback to be evaluated. - * @param array $_data_ additional parameters to be passed to the above expression/callback. - * @return mixed the expression result - */ - public function evaluateExpression($_expression_, $_data_=array()) - { - if (is_string($_expression_)) { - extract($_data_); - return eval('return ' . $_expression_ . ';'); - } - else { - $_data_[] = $this; - return call_user_func_array($_expression_, $_data_); - } - } } diff --git a/framework/base/Dictionary.php b/framework/base/Dictionary.php index bae3db0..499ddcd 100644 --- a/framework/base/Dictionary.php +++ b/framework/base/Dictionary.php @@ -31,7 +31,7 @@ namespace yii\base; * @author Qiang Xue * @since 2.0 */ -class Dictionary extends Component implements \IteratorAggregate, \ArrayAccess, \Countable +class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Countable { /** * @var array internal data storage @@ -140,12 +140,19 @@ class Dictionary extends Component implements \IteratorAggregate, \ArrayAccess, } /** - * Removes all items in the dictionary. + * Removes all items from the dictionary. + * @param boolean $safeClear whether to clear every item by calling [[remove]]. + * Defaults to false, meaning all items in the dictionary will be cleared directly + * without calling [[remove]]. */ - public function clear() + public function clear($safeClear = false) { - foreach (array_keys($this->_d) as $key) { - $this->remove($key); + if ($safeClear) { + foreach (array_keys($this->_d) as $key) { + $this->remove($key); + } + } else { + $this->_d = array(); } } diff --git a/framework/base/Event.php b/framework/base/Event.php index c7ec777..afe7e57 100644 --- a/framework/base/Event.php +++ b/framework/base/Event.php @@ -22,7 +22,7 @@ namespace yii\base; * @author Qiang Xue * @since 2.0 */ -class Event extends Component +class Event extends Object { /** * @var string the event name. This property is set by [[Component::raiseEvent]]. diff --git a/framework/base/Initable.php b/framework/base/Initable.php index c91cb03..fcbdd92 100644 --- a/framework/base/Initable.php +++ b/framework/base/Initable.php @@ -13,7 +13,7 @@ namespace yii\base; * Initable is an interface indicating a class needs initialization to work properly. * * Initable requires a class to implement the [[init]] method. - * When [[\Yii::createComponent]] is being used to create a new component which implements + * When [[\Yii::create]] is being used to create a new component which implements * Initable, it will call the [[init]] method after setting the initial values of the * component properties. * @@ -24,7 +24,7 @@ interface Initable { /** * Initializes this component. - * This method is invoked by [[\Yii::createComponent]] after its creates the new + * This method is invoked by [[\Yii::create]] after its creates the new * component instance and initializes the component properties. In other words, * at this stage, the component has been fully configured. */ diff --git a/framework/base/Model.php b/framework/base/Model.php index 040e229..78bcfbf 100644 --- a/framework/base/Model.php +++ b/framework/base/Model.php @@ -52,7 +52,7 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc /** * Initializes this model. * - * This method is required by the [[Initable]] interface. It is invoked by [[\Yii::createComponent]] + * This method is required by the [[Initable]] interface. It is invoked by [[\Yii::create]] * after its creates the new model instance and initializes the model properties. * * The default implementation calls [[behaviors]] and registers any available behaviors. diff --git a/framework/base/Module.php b/framework/base/Module.php index 44de4f0..521db25 100644 --- a/framework/base/Module.php +++ b/framework/base/Module.php @@ -257,9 +257,9 @@ abstract class Module extends Component $class = $config['class']; unset($config['class'], $config['enabled']); if ($this === Yii::app()) - $module = Yii::createComponent($class, $id, null, $config); + $module = Yii::create($class, $id, null, $config); else - $module = Yii::createComponent($class, $this->getId() . '/' . $id, $this, $config); + $module = Yii::create($class, $this->getId() . '/' . $id, $this, $config); return $this->_modules[$id] = $module; } } @@ -362,7 +362,7 @@ abstract class Module extends Component { Yii::trace("Loading \"$id\" application component", 'system.CModule'); unset($config['enabled']); - $component = Yii::createComponent($config); + $component = Yii::create($config); $component->init(); return $this->_components[$id] = $component; } diff --git a/framework/base/Object.php b/framework/base/Object.php new file mode 100644 index 0000000..7130555 --- /dev/null +++ b/framework/base/Object.php @@ -0,0 +1,282 @@ +_label; + * } + * + * public function setLabel($value) + * { + * $this->_label = $value; + * } + * ~~~ + * + * A property can be accessed like a member variable of an object. + * Reading or writing a property will cause the invocation of the corresponding + * getter or setter method. For example, + * + * ~~~ + * // equivalent to $label = $object->getLabel(); + * $label = $object->label; + * // equivalent to $object->setLabel('abc'); + * $object->label = 'abc'; + * ~~~ + * + * If a property only has a getter method and has no setter method, it is + * considered as *read-only*. In this case, trying to modify the property value + * will cause an exception. + * + * Property names are *case-insensitive*. + * + * One can call [[hasProperty]], [[canGetProperty]] and/or [[canSetProperty]] + * to check the existence of a property. + * + * Besides the property feature, the Object class defines a static method + * [[create]] which provides a convenient alternative way of creating a new + * object instance. + * + * The Object class also defines the [[evaluateExpression]] method so that a PHP + * expression or callback can be dynamically evaluated within the context of an object. + * + * @author Qiang Xue + * @since 2.0 + */ +class Object +{ + /** + * Returns the value of a object property. + * + * Do not call this method directly as it is a PHP magic method that + * will be implicitly called when executing `$value = $object->property;`. + * @param string $name the property name + * @return mixed the property value, event handlers attached to the event, + * the named behavior, or the value of a behavior's property + * @throws Exception if the property is not defined + * @see __set + */ + public function __get($name) + { + $getter = 'get' . $name; + if (method_exists($this, $getter)) { + return $this->$getter(); + } + throw new Exception('Getting unknown property: ' . get_class($this) . '.' . $name); + } + + /** + * Sets value of a object property. + * + * Do not call this method directly as it is a PHP magic method that + * will be implicitly called when executing `$object->property = $value;`. + * @param string $name the property name or the event name + * @param mixed $value the property value + * @throws Exception if the property is not defined or read-only. + * @see __get + */ + public function __set($name, $value) + { + $setter = 'set' . $name; + if (method_exists($this, $setter)) { + return $this->$setter($value); + } + if (method_exists($this, 'get' . $name)) { + throw new Exception('Setting read-only property: ' . get_class($this) . '.' . $name); + } else { + throw new Exception('Setting unknown property: ' . get_class($this) . '.' . $name); + } + } + + /** + * Checks if the named property is set (not null). + * + * Do not call this method directly as it is a PHP magic method that + * will be implicitly called when executing `isset($object->property)`. + * + * Note that if the property is not defined, false will be returned. + * @param string $name the property name or the event name + * @return boolean whether the named property is set (not null). + */ + public function __isset($name) + { + $getter = 'get' . $name; + if (method_exists($this, $getter)) { // property is not null + return $this->$getter() !== null; + } + return false; + } + + /** + * Sets a object property to be null. + * + * Do not call this method directly as it is a PHP magic method that + * will be implicitly called when executing `unset($object->property)`. + * + * Note that if the property is not defined, this method will do nothing. + * If the property is read-only, it will throw an exception. + * @param string $name the property name + * @throws Exception if the property is read only. + */ + public function __unset($name) + { + $setter = 'set' . $name; + if (method_exists($this, $setter)) { // write property + $this->$setter(null); + } elseif (method_exists($this, 'get' . $name)) { + throw new Exception('Unsetting read-only property: ' . get_class($this) . '.' . $name); + } + } + + /** + * Returns a value indicating whether a property is defined. + * A property is defined if there is a getter or setter method + * defined in the class. Note that property names are case-insensitive. + * @param string $name the property name + * @return boolean whether the property is defined + * @see canGetProperty + * @see canSetProperty + */ + public function hasProperty($name) + { + return $this->canGetProperty($name) || $this->canSetProperty($name); + } + + /** + * Returns a value indicating whether a property can be read. + * A property can be read if the class has a getter method + * for the property name. Note that property name is case-insensitive. + * @param string $name the property name + * @return boolean whether the property can be read + * @see canSetProperty + */ + public function canGetProperty($name) + { + return method_exists($this, 'get' . $name); + } + + /** + * Returns a value indicating whether a property can be set. + * A property can be written if the class has a setter method + * for the property name. Note that property name is case-insensitive. + * @param string $name the property name + * @return boolean whether the property can be written + * @see canGetProperty + */ + public function canSetProperty($name) + { + return method_exists($this, 'set' . $name); + } + + /** + * Evaluates a PHP expression or callback under the context of this object. + * + * Valid PHP callback can be class method name in the form of + * array(ClassName/Object, MethodName), or anonymous function. + * + * If a PHP callback is used, the corresponding function/method signature should be + * + * ~~~ + * function foo($param1, $param2, ..., $object) { ... } + * ~~~ + * + * where the array elements in the second parameter to this method will be passed + * to the callback as `$param1`, `$param2`, ...; and the last parameter will be the object itself. + * + * If a PHP expression is used, the second parameter will be "extracted" into PHP variables + * that can be directly accessed in the expression. + * See [PHP extract](http://us.php.net/manual/en/function.extract.php) + * for more details. In the expression, the object can be accessed using `$this`. + * + * @param mixed $_expression_ a PHP expression or PHP callback to be evaluated. + * @param array $_data_ additional parameters to be passed to the above expression/callback. + * @return mixed the expression result + */ + public function evaluateExpression($_expression_, $_data_=array()) + { + if (is_string($_expression_)) { + extract($_data_); + return eval('return ' . $_expression_ . ';'); + } else { + $_data_[] = $this; + return call_user_func_array($_expression_, $_data_); + } + } + + /** + * Creates a new object instance. + * + * This method calls [[\Yii::create]] to create the new object instance. + * + * This method differs from the PHP `new` operator in that it does the following + * steps to create a new object instance: + * + * - Call class constructor (same the `new` operator); + * - Initialize the object properties using the name-value pairs given as the + * last parameter to this method; + * - Call [[Initable::init|init]] if the class implements [[Initable]]. + * + * Parameters passed to this method will be used as the parameters to the object + * constructor. + * + * Additionally, one can pass in an associative array as the last parameter to + * this method. This method will treat the array as name-value pairs that initialize + * the corresponding object properties. For example, + * + * ~~~ + * class Foo extends \yii\base\Object + * { + * public $c; + * public function __construct($a, $b) + * { + * ... + * } + * } + * + * $model = Foo::create(1, 2, array('c' => 3)); + * // which is equivalent to the following lines: + * $model = new Foo(1, 2); + * $model->c = 3; + * ~~~ + * + * @return object the created object + * @throws Exception if the configuration is invalid. + */ + public static function create() + { + $class = '\\' . get_called_class(); + if (($n = func_num_args()) > 0) { + $args = func_get_args(); + if (is_array($args[$n-1])) { + // the last parameter could be configuration array + $method = new \ReflectionMethod($class, '__construct'); + if ($method->getNumberOfParameters()+1 == $n) { + $config = $args[$n-1]; + array_pop($args); + } + } + $config['class'] = $class; + array_unshift($args, $config); + return call_user_func_array('\Yii::create', $args); + } else { + return \Yii::create($class); + } + } +} diff --git a/framework/base/Vector.php b/framework/base/Vector.php index fea1c8b..44d87ed 100644 --- a/framework/base/Vector.php +++ b/framework/base/Vector.php @@ -37,7 +37,7 @@ namespace yii\base; * @author Qiang Xue * @since 2.0 */ -class Vector extends Component implements \IteratorAggregate, \ArrayAccess, \Countable +class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Countable { /** * @var array internal data storage @@ -193,11 +193,19 @@ class Vector extends Component implements \IteratorAggregate, \ArrayAccess, \Cou /** * Removes all items from the vector. + * @param boolean $safeClear whether to clear every item by calling [[removeAt]]. + * Defaults to false, meaning all items in the vector will be cleared directly + * without calling [[removeAt]]. */ - public function clear() + public function clear($safeClear = false) { - for ($i = $this->_c-1;$i >= 0;--$i) { - $this->removeAt($i); + if ($safeClear) { + for ($i = $this->_c-1;$i >= 0;--$i) { + $this->removeAt($i); + } + } else { + $this->_d = array(); + $this->_c = 0; } } diff --git a/framework/db/dao/Connection.php b/framework/db/dao/Connection.php index 0dfdb53..c47b363 100644 --- a/framework/db/dao/Connection.php +++ b/framework/db/dao/Connection.php @@ -227,7 +227,7 @@ class Connection extends \yii\base\ApplicationComponent /** * @var array mapping between PDO driver names and [[Schema]] classes. * The keys of the array are PDO driver names while the values the corresponding - * schema class name or configuration. Please refer to [[\Yii::createComponent]] for + * schema class name or configuration. Please refer to [[\Yii::create]] for * details on how to specify a configuration. * * This property is mainly used by [[getSchema]] when fetching the database schema information. @@ -463,7 +463,7 @@ class Connection extends \yii\base\ApplicationComponent else { $driver = $this->getDriverName(); if (isset($this->schemaMap[$driver])) { - return $this->_schema = \Yii::createComponent($this->schemaMap[$driver], $this); + return $this->_schema = \Yii::create($this->schemaMap[$driver], $this); } else { throw new Exception("Connection does not support reading schema for '$driver' database."); diff --git a/framework/logging/Router.php b/framework/logging/Router.php index fa08a2c..e84580c 100644 --- a/framework/logging/Router.php +++ b/framework/logging/Router.php @@ -101,7 +101,7 @@ class Router extends \yii\base\ApplicationComponent * Sets the log targets. * @param array $config list of log target configurations. Each array element * represents the configuration for creating a single log target. It will be - * passed to [[\Yii::createComponent]] to create the target instance. + * passed to [[\Yii::create]] to create the target instance. */ public function setTargets($config) { @@ -110,7 +110,7 @@ class Router extends \yii\base\ApplicationComponent $this->_targets[$name] = $target; } else { - $this->_targets[$name] = \Yii::createComponent($target); + $this->_targets[$name] = \Yii::create($target); } } } diff --git a/framework/validators/Validator.php b/framework/validators/Validator.php index 30aab52..bba109a 100644 --- a/framework/validators/Validator.php +++ b/framework/validators/Validator.php @@ -166,7 +166,7 @@ abstract class Validator extends \yii\base\Component foreach ($params as $name => $value) { $config[$name] = $value; } - $validator = \Yii::createComponent($config); + $validator = \Yii::create($config); return $validator; }