国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

淺析Yii2.0的行為Behavior

legendmohe / 2090人閱讀

摘要:概念理解使用行為可以在不修改現(xiàn)有類的情況下,對(duì)類的功能進(jìn)行擴(kuò)充。最后將行為名稱和行為實(shí)例放到的屬性中,至此,行為的綁定就結(jié)束了。不過在解除的時(shí)候雖然都是刪掉相應(yīng)的,但是解除行為還需要解除在綁定行為的時(shí)候綁定的事件,這點(diǎn)不太一樣。

概念理解:使用行為(behavior)可以在不修改現(xiàn)有類的情況下,對(duì)類的功能進(jìn)行擴(kuò)充。 通過將行為綁定到一個(gè)類,可以使類具有行為本身所定義的屬性和方法,就好像類本來就有這些屬性和方法一樣。 而不需要寫一個(gè)新的類去繼承或包含現(xiàn)有類。在功能上類似于 Traits ,達(dá)到類似于多繼承的目的。
行為的實(shí)現(xiàn)demo
 "afterAttach"
        ];
    }

    public function afterAttach()
    {
        echo "事件已觸發(fā)";
    }
}

// 在控制器或者命令行下調(diào)用

$myClass = new MyClass();

$myBehavior = new BehaviorTest();

// 將行為綁定到 MyClass 的實(shí)例
$myClass->attachBehavior("test", $myBehavior);

// MyClass 實(shí)例調(diào)用行為類中的屬性
echo $myClass->_val;

// MyClass 實(shí)例調(diào)用行為類中的方法
$myClass->getOutput();

// MyClass 實(shí)例觸發(fā)行為類中定義的事件
$myClass->trigger(BehaviorTest::EVENT_AFTER_SAVE);
行為的綁定原理

我們先來看一下 $myClass->attachBehavior("test", $myBehavior); 行為綁定的時(shí)候做了哪些事情?好的,又是我們的老朋友yiiaseComponent

// yiiaseComponent 的部分代碼

private $_behaviors;

public function behaviors()
{
    return [];
}

public function attachBehavior($name, $behavior)
{
        $this->ensureBehaviors();
        return $this->attachBehaviorInternal($name, $behavior);
}

public function ensureBehaviors()
{
        if ($this->_behaviors === null) {
            $this->_behaviors = [];
            foreach ($this->behaviors() as $name => $behavior) {
                $this->attachBehaviorInternal($name, $behavior);
            }
        }
}

private function attachBehaviorInternal($name, $behavior)
{
    if (!($behavior instanceof Behavior)) {
        $behavior = Yii::createObject($behavior);
    }
    if (is_int($name)) {
        $behavior->attach($this);
        $this->_behaviors[] = $behavior;
    } else {
        if (isset($this->_behaviors[$name])) {
            $this->_behaviors[$name]->detach();
        }
        $behavior->attach($this);

        $this->_behaviors[$name] = $behavior;
    }

    return $behavior;
}

$myClass 調(diào)用 attachBehavior() 傳入倆個(gè)參數(shù),一個(gè)是行為名稱,另一個(gè)是行為類的名稱或?qū)嵗蛘呤菙?shù)組,接著 attachBehavior() 調(diào)用了 ensureBehaviors(),這個(gè)函數(shù)我們暫時(shí)用不到,因?yàn)槲覀儧]有在MyClass里面重載behaviors(),不過也能大概猜到ensureBehaviors()的用途了。再往下調(diào)用的是私有函數(shù)attachBehaviorInternal(),這個(gè)函數(shù)先判斷傳進(jìn)來的$behavior 是否已實(shí)例化,如果還沒有則進(jìn)行實(shí)例化,再通過$name判斷是匿名行為還是命名行為,如果是命名行為,需要查看是否已經(jīng)綁定同名的行為,如果綁定了同名的行為,會(huì)將以前的行為先解綁再調(diào)用$behavior->attach($this);[注:這里$this指的MyClass實(shí)例,也就是$myClass],這樣我們就來到了yiiaseBehaviorattach()方法,下面是attach()方法的源碼:

public function attach($owner)
{
    $this->owner = $owner;
    foreach ($this->events() as $event => $handler) {
        $owner->on($event, is_string($handler) ? [$this, $handler] : $handler);
    }
}

$this->owner = $owner;[注:這里$this 指的是$behavior也就是類BehaviorTest的實(shí)例],這句代碼指定了行為類的主人是誰,后面的代碼看著似乎似曾相識(shí)?是的,就是將行為類events()方法里面的事件也綁定的宿主身上,這里不具體展開,有興趣的小伙伴可以看一下淺析Yii2.0的事件Event。最后將行為名稱和行為實(shí)例放到$myClass的屬性_behavior中,至此,行為的綁定就結(jié)束了。好像也沒干什么啊,我們現(xiàn)在可以打印一下$myClass的數(shù)據(jù)結(jié)構(gòu)是怎樣的?

commoncomponentsMyClass Object
(
    [_events:yiiaseComponent:private] => Array
        (
            [eventAfterAttach] => Array
                (
                    [0] => Array
                        (
                            [0] => Array
                                (
                                    [0] => commoncomponentsBehaviorTest Object
                                        (
                                            [_val] => 我是BehaviorTest里面的公有屬性_val
                                            [owner] => commoncomponentsMyClass Object
 *RECURSION*
                                        )

                                    [1] => afterAttach
                                )

                            [1] => 
                        )

                )

        )

    [_eventWildcards:yiiaseComponent:private] => Array
        (
        )

    [_behaviors:yiiaseComponent:private] => Array
        (
            [test] => commoncomponentsBehaviorTest Object
                (
                    [_val] => 我是BehaviorTest里面的公有屬性_val                   
                    [owner] => commoncomponentsMyClass Object
 *RECURSION*
                )

        )

)

可以看到$myClass已經(jīng)綁定了一個(gè)行為test,綁定了一個(gè)事件eventAfterAttach,那么綁定行為以后,是怎么調(diào)用行為類里面的屬性和方法呢?

行為的使用原理

還是看一下demo里面$myClass->_val這句代碼是怎么執(zhí)行的?根據(jù)上面$myClass的數(shù)據(jù)結(jié)構(gòu)可以看出并沒有_val這個(gè)屬性,但是yiiaseComponent里面實(shí)現(xiàn)了__get()這個(gè)魔術(shù)方法,我們看一下源碼。

public function __get($name)
{
    $getter = "get" . $name;
    if (method_exists($this, $getter)) {
        // read property, e.g. getName()
        return $this->$getter();
    }

    // behavior property
    $this->ensureBehaviors();
    foreach ($this->_behaviors as $behavior) {
        if ($behavior->canGetProperty($name)) {
            return $behavior->$name;
        }
    }

    if (method_exists($this, "set" . $name)) {
        throw new InvalidCallException("Getting write-only property: " . get_class($this) . "::" . $name);
    }

    throw new UnknownPropertyException("Getting unknown property: " . get_class($this) . "::" . $name);
}

又似曾相識(shí)?是的,跟yiiaseBaseObject里面屬性的實(shí)現(xiàn)類似,有興趣的小伙伴可以看一下淺析Yii2.0的屬性Property。然后直接看注釋behavior property部分,又去調(diào)用了ensureBehaviors(),先不管,接著又去遍歷_behaviors這個(gè)屬性,根據(jù)上面$myClass的數(shù)據(jù)結(jié)構(gòu)得知,此時(shí)foreach里面的$behavior就是行為類commoncomponentsBehaviorTest實(shí)例,先通過canGetProperty判斷_val是否可讀或者存在,大家可以去看yiiaseBaseObject里面該方法的實(shí)現(xiàn)。我們這里返回的是true,然后就直接通過commoncomponentsBehaviorTest的實(shí)例$behavior返回_val的值。

根據(jù)上面獲取行為類里面屬性的流程我們注意到:

因?yàn)槭峭ㄟ^實(shí)例化行為類去調(diào)用的屬性,所以屬性是protected或者是private是獲取不到的。

如果Component綁定了多個(gè)行為,并且多個(gè)行為中有同名的屬性,那么該Component獲取的是第一個(gè)行為類里面的該屬性。

那么行為類里面的方法是怎么被調(diào)用的呢?屬性的調(diào)用是通過__get()來實(shí)現(xiàn)的,很容易聯(lián)想到方法的調(diào)用是通過__call()來實(shí)現(xiàn)的,我們查看一下yiiaseBaseObject源碼,果然里面實(shí)現(xiàn)__call()這個(gè)魔術(shù)方法,下面是源碼,然后對(duì)照上面$myClass的數(shù)據(jù)結(jié)構(gòu)一看就明白了。需要注意的是,跟上面屬性的調(diào)用一樣,方法也必須是public的,protected 、private方法是調(diào)用不了的。

public function __call($name, $params)
{
    $this->ensureBehaviors();
    foreach ($this->_behaviors as $object) {
        if ($object->hasMethod($name)) {
            return call_user_func_array([$object, $name], $params);
        }
    }
    throw new UnknownMethodException("Calling unknown method: " . get_class($this) . "::$name()");
}

注意到__call()里面又有一個(gè)老朋友ensureBehaviors()這個(gè)函數(shù)似乎無處不在?是的,查看一下yiiaseComponent里面的源碼我們可以發(fā)現(xiàn)所有的公有方法都調(diào)用了這個(gè)函數(shù),那么這個(gè)函數(shù)到底是干嘛的呢,其實(shí)demo里面綁定行為的方式可以稱為主動(dòng)綁定,就是我們主動(dòng)調(diào)用函數(shù)attachBehavior()去綁定行為的,對(duì)應(yīng)的就是被動(dòng)綁定了,實(shí)現(xiàn)方式就是在待綁定行為的類里面重載behaviors()這個(gè)函數(shù)就可以實(shí)現(xiàn)綁定了,相當(dāng)于一個(gè)行為的配置項(xiàng)。倆種綁定方式看個(gè)人喜好了,如果一個(gè)類需要綁定的行為很明確,推薦使用配置項(xiàng)的方法去綁定,也就是被動(dòng)綁定。下面是將demo里面的綁定方式改成被動(dòng)綁定。

 new BehaviorTest()
        ];
    }
}

此時(shí)可以將demo中 $myClass->attachBehavior("test", $myBehavior); 這句代碼去掉,$myClass也是同樣可以調(diào)用類 BehaviorTest 里面的屬性和方法
小結(jié)

這倆天查看了Yii2.0事件、行為的實(shí)現(xiàn)方式,覺得有很多相似的地方,都是通過yiiaseComponent來實(shí)現(xiàn)的,通過打印的數(shù)據(jù)結(jié)構(gòu)也可以看到,Component主要就是圍繞_events _eventWildcards _behaviors這三個(gè)屬性展開的,其中第二個(gè)屬性是 事件的通配符模式,也可以歸屬到 事件中,那么這樣Component的主要功能就是就是實(shí)現(xiàn)了 事件和行為。并且實(shí)現(xiàn)原理上也是相似的,都是往Component里面綁定事件和行為的handle,然后觸發(fā)事件或者行為的時(shí)候,再去回調(diào)相應(yīng)的handle。不過在解除的時(shí)候雖然都是刪掉相應(yīng)的handle,但是解除行為還需要解除在綁定行為的時(shí)候綁定的事件,這點(diǎn)不太一樣。

以上總結(jié)參考了深入理解Yii2.0,其實(shí)以前就看過,但是也只是局限于看過,沒有自己跑demo調(diào)試、查看源代碼,然后就誤以為自己明白了,其實(shí)過倆天什么都不記得了。所以現(xiàn)在通過寫博客來加深自己的理解,由于水平有限,歡迎小伙伴交流和指正。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/31590.html

相關(guān)文章

  • 淺析Yii2.0屬性Property

    摘要:概念理解第一次看深入理解的時(shí)候,我也是懵逼的,屬性不就是類的屬性嗎,有什么好說的。屬性的實(shí)現(xiàn)步驟繼承自。聲明一個(gè)用于保存該屬性的私有成員變量。如果只提供了,那么該屬性為只讀屬性,只提供了,則為只寫。 概念理解:第一次看深入理解Yii2.0的時(shí)候,我也是懵逼的,屬性不就是類的屬性嗎,有什么好說的。后來才知道Yii框架對(duì)成員變量和屬性做了區(qū)分,那類的成員變量和屬性到底是什么關(guān)系又有什么區(qū)別...

    arashicage 評(píng)論0 收藏0
  • 淺析Yii2.0事件Event

    摘要:全局級(jí)別利用實(shí)例在整個(gè)應(yīng)用的生命周期中全局可訪問的特性,來實(shí)現(xiàn)這個(gè)全局事件的。類級(jí)別通過維護(hù)類的屬性數(shù)組,觸發(fā)事件時(shí)通過類名和事件名稱取到當(dāng)前類以及父類的數(shù)據(jù),再通過函數(shù)觸發(fā)。 概念理解:在某一個(gè)事件(trigger)發(fā)生的時(shí)候,觸發(fā)預(yù)先設(shè)定(on)的代碼,這是代碼解耦的一種方式。 事件按照級(jí)別分為三類 1. 實(shí)例級(jí)別 綁定事件、觸發(fā)事件的類繼承的是Component,只在當(dāng)前示例中運(yùn)...

    李義 評(píng)論0 收藏0
  • Yii源碼解讀-行為

    摘要:行為所要響應(yīng)的事件重載方法,表示這個(gè)行為將對(duì)類何種事件進(jìn)行何種反饋。行為用的最多的,也是對(duì)于各種事件的響應(yīng)。當(dāng)出現(xiàn)命名沖突時(shí),行為會(huì)自行排除沖突,自動(dòng)使用先綁定的行為。目前還沒有能支持行為。 Yii基礎(chǔ) 行為(Behavior) 行為(behavior)可以在不修改現(xiàn)有類的情況下,對(duì)類的功能進(jìn)行擴(kuò)充。 通過將行為綁定到一個(gè)類,可以使類具有行為本身所定義的屬性和方法,就好像類本來就有這些...

    IntMain 評(píng)論0 收藏0
  • 游戲AI—行為樹研究及實(shí)現(xiàn)

    摘要:另外,當(dāng)并行器滿足條件提前退出時(shí),所有正在執(zhí)行的子行為也應(yīng)該立即被終止,我們?cè)诤瘮?shù)中調(diào)用每個(gè)子節(jié)點(diǎn)的終止方法監(jiān)視器監(jiān)視器是并行器的應(yīng)用之一,通過在行為運(yùn)行過程中不斷檢查是否滿足某條件,如果不滿足則立刻退出。將條件放在并行器的尾部即可。 從上古卷軸中形形色色的人物,到NBA2K中揮灑汗水的球員,從使命召喚中詭計(jì)多端的敵人,到刺客信條中栩栩如生的人群。游戲AI幾乎存在于游戲中的每個(gè)角落,默...

    Harriet666 評(píng)論0 收藏0
  • 使用 CSS overscroll-behavior 控制滾動(dòng)行為:自定義下拉刷新和溢出效果

    摘要:否則會(huì)出現(xiàn)兩個(gè)下拉刷新之前之后禁用炫光和回彈效果將屬性制定為,可以禁用默認(rèn)的滾動(dòng)邊界效果。完整的地址源碼最終效果閱讀原文討論地址使用控制滾動(dòng)行為自定義下拉刷新和溢出效果如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里 dev-reading/fe 是一個(gè)閱讀、導(dǎo)讀、速讀的 repo,不要依賴于 dev-reading/fe 學(xué)習(xí)知識(shí)。本 repo 只是一個(gè)快速了解文章內(nèi)容的工具,并不提供全文解讀和翻譯。你...

    jhhfft 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

legendmohe

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<