yii2

无人久伴 提交于 2019-11-27 00:22:26

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 提供扩展服务的

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!