yii2 内部规定了 __construct 函数的构造形式,以键值对儿数组作为参数,进行属性的初始化,但要注意给属性赋值的工作是转交给基类 yii\base\Yii::configure 方法的,故无法直接访问本类的私有属性进行初始化工作 ,但我们可以使用属性的 setter/getter 方法来完成
yii\base\Object
yii2 在实例化一个类时可以将此类的属性以 key=>value 的数组形式传参初始化本类的一些属性
所有的组件的构造函数都继承至 yii\base\Object::__construct()
这里需要注意的是,yii2 以安全为原则,并没有将类的私有属性开放给初始化的参数数组,原因是 __construct 中的初始工作是调用的 yii\base\Yii::configure() 方法,上下文切换到本类外部,无法访问私有变量(这里便引出了 php 的私有变量访问域和 __set/__get魔术方法)
/**
* Constructor.
* The default implementation does two things:
*
* - Initializes the object with the given configuration `$config`.
* - Call [[init()]].
*
* If this method is overridden in a child class, it is recommended that
*
* - the last parameter of the constructor is a configuration array, like `$config` here.
* - call the parent implementation at the end of the constructor.
*
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($config = [])
{
if (!empty($config)) {
//转到外部调用,故无法直接访问当前需要用来初始的 $this 的私有属性
Yii::configure($this, $config);
}
$this->init();
}
如何初始化私有属性
私有属性只能在类内部被直接访问,同时我们也可以通过 php 的 __set/__get 魔术方法对其进行封装访问
yii2 的 setter/getter 方法
yii2 的属性有一套 setter/getter 方法用来承接外部访问本类的私有属性,其是对 php 的 __set/__get 魔术方法的封装,当我们访问类的私有属性时,会触发 __set/__get 方法,在 yii\base\Object 中
/**
* Returns the value of an 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
* @throws UnknownPropertyException if the property is not defined
* @throws InvalidCallException if the property is write-only
* @see __set()
*/
public function __get($name)
{
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
return $this->$getter();
} elseif (method_exists($this, 'set' . $name)) {
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
}
/**
* Sets value of an 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 UnknownPropertyException if the property is not defined
* @throws InvalidCallException if the property is read-only
* @see __get()
*/
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
可见 yii2 会去检测是否设定了此类某私有属性的 setter/getter 方法,如果存在则可以进行访问,注意 php 的函数/方法/类名是不区分大小写的,setName 和 setname 没什么区别....注意就好,设定了私有属性的 setter/getter 接口方法,在实例化时参数数组也可以包含私有属性的值了,推荐此类方法,在封装的同时也没有破坏yii2框架的统一性
扩展继承至yii\base\Object::__construct()
public function __construct(array $config, $name)
{
parent::__construct($config);
$this->_name= $name;
}
如上所示,我们在继承父类的构造方法的同时,自己增加新的构造参数,来传递给我们本类的私有变量,但这样写向下兼容性会变得很差,不推荐
yii\base\Component::setter/getter
这里要单独说一下 Component 的 setter/getter 方法,Component 对 Object 的 setter/getter 方法进行了重写,以满足自己除 属性 Property 外的 Event 和 Behavior 的配置
yii\base\Object
|--yii\base\Event
|--yii\base\Behavior
|--yii\bae\Component
基础的 setter/getter 方法定义在 yii\base\Object 并被其下三大基类继承,但并不能满足组件 Component 的配置,因为 Component 组件还包含了 Event 和 Behavior 等配置项的设定
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
// set property
$this->$setter($value);
return;
} elseif (strncmp($name, 'on ', 3) === 0) {
// on event: attach event handler
$this->on(trim(substr($name, 3)), $value);
return;
} elseif (strncmp($name, 'as ', 3) === 0) {
// as behavior: attach behavior
$name = trim(substr($name, 3));
$this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value));
return;
} else {
// behavior property
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->canSetProperty($name)) {
$behavior->$name = $value;
return;
}
}
}
if (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
//创建一个组件的对象,并为其设定 on 类的事件 和 as 类的行为
\Yii::createObject([
"class" => "app\utils\MyTool",
"param_1" => $value_1,
"param_2" => $value_2,
"on begin" => ['app\utils\MyTool', 'beginHandler'],
"on end" => ['app\utils\MyTool', 'endHandler'],
"as doIt" => [
"class" => "app\behaviors\MyBehavior"
]
]);
可以看到,当组件初始化时,根据配置参数的格式会路由 on / as 类的配置项至 Event / Behavior 的设定,Event 和 Behaviour 都是为 Component 提供扩展服务的
来源:oschina
链接:https://my.oschina.net/u/252076/blog/682377