搜尋
首頁後端開發php教程深入理解PHP中七個預定義介面

深入理解PHP中七個預定義介面

深入瞭解預定義介面

#場景:平常工作中寫的都是業務模組,很少會去實現這樣的接口,但是在框架裡面用的倒是很多。

 

1. Traversable(遍歷)介面

該介面不能被類別直接實現,如果直接寫了一個普通類別實現了該遍歷接口,是會直接報致命的錯誤,提示使用Iterator(迭代器接口)或者IteratorAggregate(聚合迭代器接口)來實現,這兩個接口後面會介紹;所有通常情況下,我們只是會用來判斷該類是否可以使用foreach 來進行遍歷;

class Test implements Traversable
    {
    }
    上面这个是错误示范,该代码会提示这样的错误:
    Fatal error: Class Test must implement interface Traversable as part of either Iterator or 
    IteratorAggregate in Unknown on line 0

上面的大致意思是說如要實現這個接口,必須同Iterator或者IteratorAggregate來實現

正確的做法:

當我們要判斷一個類別是否可以使用foreach來進行遍歷,只需要判斷是否是traversable的實例

     class Test
     {
     }
     $test = new Test;
     var_dump($test instanceOf Traversable);

2. Iterator(迭代器)介面

迭代器介面其實實作的原理就是類似指標的移動,當我們寫一個類別的時候,透過實作對應的5 個方法:key(),current(),next(),rewind(),valid(),就可以實現資料的迭代移動,請看以下程式碼

<?php
    class Test implements Iterator
    {
        private $key;
        private $val = [
            &#39;one&#39;,
            &#39;two&#39;,
            &#39;three&#39;,
        ];

        public function key()
        {
            return $this->key;
        }

        public function current()
        {
            return $this->val[$this->key];
        }

        public function next()
        {
            ++$this->key;
        }

        public function rewind()
        {
            $this->key = 0;
        }

        public function valid()
        {
            return isset($this->val[$this->key]);
        }
    }

    $test = new Test;

    $test->rewind();

    while($test->valid()) {
        echo $test->key . &#39;:&#39; . $test->current() . PHP_EOL;
        $test->next();
    }

  ## 這個輸出結果:       

        0: one
        1: two
        2: three

  看了這個原理我們就知道,其實迭代的移動方式:rewind()-> valid()->key() -> current() -> next() ->valid()-> key() ....-> valid();

好的,理解了上面,我們打開Iterator的接口,發現它是實現了Traversable(遍歷)接口的,接下來我們來證明下:

var_dump($test instanceOf Traversable);

  結果返回的是true,證明這個類的對象是可以進行遍歷的。

 foreach ($test as $key => $value){
         echo $test->key . &#39;:&#39; . $test->current() . PHP_EOL;
  }

 這個的結果跟while循環實現的模式是一樣的。

 

3. IteratorAggregate(聚合迭代器) 介面

聚合迭代器和迭代器的原理是一樣的,只不過聚合迭代器已經實現了迭代器原理,你只需要實作一個getIterator()方法來實現迭代,具體看以下程式碼

<?php
    class Test implements IteratorAggregate
    {
        public $one = 1;
        public $two = 2;
        public $three = 3;

        public function __construct()
        {
            $this->four = 4;
        }

        public function getIterator()
        {
            return new AraayIterator($this);
        }
    }

    $test = (new Test())->getIterator();
    $test->rewind();
    while($test->valid()) {
        echo $test->key() . &#39; : &#39;  .  $test->current() . PHP_EOL;
        $test->next();
    }

    从上面的代码,我们可以看到我们将Test类的对象传进去当做迭代器,通过while循环的话,我们必须通过调用getIterator()方法获取到迭代器对象,然后直接进行迭代输出,而不需要去实现相关的key()等方法。
    当然这个时候,我们肯定想知道是否可以直接从foreach进行迭代循环出去呢?那么我们来打印一下结果

    $test = new Test;
    var_dump($test instanceOf Traversable);

    结果是输出bool true,所以我们接下来是直接用foreach来实现一下。

    $test = new Test;
  foreach($test as $key => $value) {
     echo $key . &#39; : &#39; . $value  .  PHP_EOL;
  }

 接下来,我们看到是对对象进行迭代,这个时候我们是否可以数组进行迭代呢?

 class Test implements IteratorAggregate
 {
    public $data;

    public function __construct()
    {
        $this->data = [&#39;&#39;one&#39; =>  1 , &#39;two&#39; => 2];
    }

    public function getIterator()
    {
        return new AraayIterator($this->data);
    }
 }

 同理实现的方式跟对对象进行迭代是一样的。

 

很多PHPer在進階的時候總是會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裡入手去提升,對此我整理了一些資料,包括但不限於:分散式架構、高可擴展、高性能、高同時、伺服器效能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高階進階乾貨需要的可以免費分享給大家,需要的加群(點選→)677079770

4. ArrayAccess(陣列式存取)介面

通常情況下,我們會看到this ['name '] 這樣的用法,但是我們知道,$this 是一個對象,是如何使用數組方式存取的?答案就是實作了資料組存取介面ArrayAccess,具體程式碼如下

<?php
    class Test implements ArrayAccess
    {
        public $container;

        public function __construct()
        {
            $this->container = [
                &#39;one&#39; => 1,
                &#39;two&#39; => 2,
                &#39;three&#39;  => 3,
            ];
        }

        public function offsetExists($offset) 
        {
            return isset($this->container[$offset]);
        }

        public function offsetGet($offset)
        {
            return isset($this->container[$offset]) ? $this->container[$offset] : null;
        }

        public function offsetSet($offset, $value)
        {
            if (is_null($offset)) {
                $this->container[] = $value;
            } else {
                $this->container[$offset] = $value;
            }
        }

        public function offsetUnset($offset)
        {
            unset($this->container[$offset]);
        }
    }
   $test = new Test;
   var_dump(isset($test[&#39;one&#39;]));
   var_dump($test[&#39;two&#39;]);
   unset($test[&#39;two&#39;]);
   var_dump(isset($test[&#39;two&#39;]));
   $test[&#39;two&#39;] = 22;
   var_dump($test[&#39;two&#39;]);
   $test[] = 4;
   var_dump($test);
   var_dump($test[0]);

   当然我们也有经典的一个做法就是把对象的属性当做数组来访问

   class Test implements ArrayAccess
   {
        public $name;

        public function __construct()
        {
            $this->name = &#39;gabe&#39;;  
        }

        public function offsetExists($offset)
        {
            return isset($this->$offset);
        }

        public function offsetGet($offset)
        {
            return isset($this->$offset) ? $this->$offset : null;
        }

        public function offsetSet($offset, $value)
        {
            $this->$offset = $value;
        }

        public function offsetUnset($offset)
        {
            unset($this->$offset);
        }
   }

  $test = new Test;
  var_dump(isset($test[&#39;name&#39;]));
  var_dump($test[&#39;name&#39;]);
  var_dump($test[&#39;age&#39;]);
  $test[1] = &#39;22&#39;;
  var_dump($test);
  unset($test[&#39;name&#39;]);
  var_dump(isset($test[&#39;name&#39;]));
  var_dump($test);
  $test[] = &#39;hello world&#39;;
  var_dump($test);

 

#5. Serializable (序列化)介面

通常情況下,如果我們的類別中定義了魔術方法,sleep(),wakeup () 的話,我們在進行serialize () 的時候,會先呼叫sleep () 的魔術方法,我們透過傳回一個數組,來定義對物件的哪些屬性進行序列化,同理,我們在調用反序列化unserialize () 方法的時候,也會先調用的wakeup()魔術方法,我們可以進行初始化,如對一個對象的屬性進行賦值等操作;但是如果這個類別實作了序列化接口,我們就必須實作serialize()方法和unserialize () 方法,同時sleep()和wakeup () 兩個魔術方法都會同時不再支援,具體程式碼看如下;

<?php
    class Test
    {    
        public $name;
        public $age;

        public function __construct()
        {
            $this->name = &#39;gabe&#39;;
            $this->age = 25; 
        }    

        public function __wakeup()
        {
            var_dump(__METHOD__); 
            $this->age++;
        }   

        public function __sleep()
        {        
            var_dump(__METHOD__);
            return [&#39;name&#39;];    
        }
    }

    $test = new Test;
    $a = serialize($test);
    var_dump($a);
    var_dump(unserialize($a));

    //实现序列化接口,发现魔术方法失效了

   class Test implements Serializable
   {    
    public $name;
    public $age;

    public function __construct()
    {        
        $this->name = &#39;gabe&#39;;
        $this->age = 25;
    } 

    public function __wakeup()
    { 
        var_dump(__METHOD__);
        $this->age++;
    }

    public function __sleep()
    {
        var_dump(__METHOD__);
        return [&#39;name&#39;];
    }

    public function serialize()
    {
        return serialize($this->name);
    } 

    public function unserialize($serialized)
    {       
        $this->name = unserialize($serialized);
        $this->age = 1;    
    }
}
$test = new Test;
$a = serialize($test);
var_dump($a);
var_dump(unserialize($a));

 

6. Closure 類別

用於代表匿名函數的類,凡是匿名函數其實回傳的都是Closure 閉包類別的實例,該類中主要有兩個方法,bindTo()和bind(),透過檢視源碼,可以發現兩個方法是殊途同歸,只不過是bind () 是個靜態方法,具體用法看如下;

<?php
    $closure = function () {
        return &#39;hello world&#39;;
    }

    var_dump($closure);
    var_dump($closure());

 

透過上面的例子,可以看出第一個印出來的是Closure 的一個實例,而第二個就是印出匿名函數傳回的hello world 字串;接下來是使用這個匿名類別的方法,這兩個方法的目的都是把匿名函數綁定一個類別上使用;

bindTo()

<?php
namespace demo1;
    class Test {
        private $name = &#39;hello woeld&#39;;
    }

    $closure = function () {
        return $this->name;
    }

    $func = $closure->bindTo(new Test);
    $func();
    // 这个是可以访问不到私有属性的,会报出无法访问私有属性
    // 下面这个是正确的做法
    $func = $closure->bindTo(new Test, Test::class);
    $func();

namespace demo2;
    class Test
    {
        private statis $name = &#39;hello world&#39;;
    }

    $closure = function () {
        return self::$name;
    }
    $func = $closure->bindTo(null, Test::class);
    $func();

 

bind()

<?php
namespace demo1;
class Test 
{
    private  $name = &#39;hello world&#39;;
}

$func = \Closure::bind(function() {
    return $this->name;
}, new Test, Test::class);

$func();

namespace demo2;
class Test 
{
    private static  $name = &#39;hello world&#39;;
}

$func = \Closure::bind(function() {
    return self::$name;
}, null, Test::class);

$func()

 

 

7. Generator (生成器)

Generator 实现了 Iterator,但是他无法被继承,同时也生成实例。既然实现了 Iterator,所以正如上文所介绍,他也就有了和 Iterator 相同的功能:rewind->valid->current->key->next...,Generator 的语法主要来自于关键字 yield。yield 就好比一次循环的中转站,记录本次的活动轨迹,返回一个 Generator 的实例。

Generator 的优点在于,当我们要使用到大数据的遍历,或者说大文件的读写,而我们的内存不够的情况下,能够极大的减少我们对于内存的消耗,因为传统的遍历会返回所有的数据,这个数据存在内存上,而 yield 只会返回当前的值,不过当我们在使用 yield 时,其实其中会有一个处理记忆体的过程,所以实际上这是一个用时间换空间的办法。

<?php
$start_time = microtime(true);
function xrange(int $num){
    for($i = 0; $i < $num; $i++) { 
        yield $i;    
    }
}
$generator = xrange(100000);
foreach ($generator as $key => $value) { 
    echo $key . &#39;: &#39; . $value . PHP_EOL;
}
echo &#39;memory: &#39; . memory_get_usage() . &#39; time: &#39;. (microtime(true) - $start_time);

 

输出:memory: 388904 time: 0.12135100364685

<?php
$start_time = microtime(true);
function xrange(int $num){
    $arr = [];    
    for($i = 0; $i < $num; $i++) { 
        array_push($arr, $i);
    } 
    return $arr;
}
$arr = xrange(100000);
foreach ($arr as $key => $value) {
    echo $key . &#39;: &#39; . $value . PHP_EOL;
}
echo &#39;memory: &#39; . memory_get_usage() . &#39; time: &#39;. (microtime(true) - $start_time);

输出:

memory: 6680312 time: 0.10804104804993

更多相关php知识,请访问php教程

以上是深入理解PHP中七個預定義介面的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:cnblogs。如有侵權,請聯絡admin@php.cn刪除
繼續使用PHP:耐力的原因繼續使用PHP:耐力的原因Apr 19, 2025 am 12:23 AM

PHP仍然流行的原因是其易用性、靈活性和強大的生態系統。 1)易用性和簡單語法使其成為初學者的首選。 2)與web開發緊密結合,處理HTTP請求和數據庫交互出色。 3)龐大的生態系統提供了豐富的工具和庫。 4)活躍的社區和開源性質使其適應新需求和技術趨勢。

PHP和Python:探索他們的相似性和差異PHP和Python:探索他們的相似性和差異Apr 19, 2025 am 12:21 AM

PHP和Python都是高層次的編程語言,廣泛應用於Web開發、數據處理和自動化任務。 1.PHP常用於構建動態網站和內容管理系統,而Python常用於構建Web框架和數據科學。 2.PHP使用echo輸出內容,Python使用print。 3.兩者都支持面向對象編程,但語法和關鍵字不同。 4.PHP支持弱類型轉換,Python則更嚴格。 5.PHP性能優化包括使用OPcache和異步編程,Python則使用cProfile和異步編程。

PHP和Python:解釋了不同的範例PHP和Python:解釋了不同的範例Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

PHP和Python:深入了解他們的歷史PHP和Python:深入了解他們的歷史Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

在PHP和Python之間進行選擇:指南在PHP和Python之間進行選擇:指南Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

PHP和框架:現代化語言PHP和框架:現代化語言Apr 18, 2025 am 12:14 AM

PHP在現代化進程中仍然重要,因為它支持大量網站和應用,並通過框架適應開發需求。 1.PHP7提升了性能並引入了新功能。 2.現代框架如Laravel、Symfony和CodeIgniter簡化開發,提高代碼質量。 3.性能優化和最佳實踐進一步提升應用效率。

PHP的影響:網絡開發及以後PHP的影響:網絡開發及以後Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP類型提示如何起作用,包括標量類型,返回類型,聯合類型和無效類型?PHP類型提示如何起作用,包括標量類型,返回類型,聯合類型和無效類型?Apr 17, 2025 am 12:25 AM

PHP類型提示提升代碼質量和可讀性。 1)標量類型提示:自PHP7.0起,允許在函數參數中指定基本數據類型,如int、float等。 2)返回類型提示:確保函數返回值類型的一致性。 3)聯合類型提示:自PHP8.0起,允許在函數參數或返回值中指定多個類型。 4)可空類型提示:允許包含null值,處理可能返回空值的函數。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境