yii2 - Property 之 默認構造方法 和 setter/getter 方法

yii2 內部規定了 __construct 函數的構造形式,以鍵值對兒數組做爲參數,進行屬性的初始化,但要注意給屬性賦值的工做是轉交給基類 yii\base\Yii::configure 方法的,故沒法直接訪問本類的私有屬性進行初始化工做 ,但咱們能夠使用屬性的 setter/getter 方法來完成php

yii\base\Object

yii2 在實例化一個類時能夠將此類的屬性以 key=>value 的數組形式傳參初始化本類的一些屬性數組

全部的組件的構造函數都繼承至 yii\base\Object::__construct()安全

這裏須要注意的是,yii2 以安全爲原則,並無將類的私有屬性開放給初始化的參數數組,緣由是 __construct 中的初始工做是調用的  yii\base\Yii::configure() 方法,上下文切換到本類外部,沒法訪問私有變量(這裏便引出了 php 的私有變量訪問域和 __set/__get魔術方法)yii2

/**
     * 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 魔術方法對其進行封裝訪問app

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

擴展繼承至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 的配置this

yii\base\Objectspa

    |--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 提供擴展服務的

相關文章
相關標籤/搜索