Heim >Backend-Entwicklung >PHP-Tutorial >Vertiefendes Verständnis der sieben vordefinierten Schnittstellen in PHP

Vertiefendes Verständnis der sieben vordefinierten Schnittstellen in PHP

藏色散人
藏色散人nach vorne
2020-01-29 14:44:211883Durchsuche

Vertiefendes Verständnis der sieben vordefinierten Schnittstellen in PHP

Tiefgehendes Verständnis vordefinierter Schnittstellen

Szenario: Bei meiner normalen Arbeit schreibe ich Geschäftsmodule, selten Wenn Sie eine solche Schnittstelle implementieren, wird sie im Framework häufig verwendet.

1. Durchlaufbare Schnittstelle

Diese Schnittstelle kann nicht direkt von einer Klasse implementiert werden, wenn Sie direkt eine normale Klasse schreiben, um die Durchquerung zu implementieren Die Schnittstelle meldet direkt einen schwerwiegenden Fehler und fordert zur Implementierung auf. Diese beiden Schnittstellen werden später eingeführt. Wir verwenden sie nur zur Beurteilung der Klasse foreach zum Durchqueren verwenden?

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

Die allgemeine Bedeutung des oben Gesagten ist, dass Sie diese Schnittstelle mit Iterator oder IteratorAggregate implementieren müssen

Der richtige Ansatz:

Wenn wir feststellen möchten, ob eine Klasse mit foreach durchlaufen werden kann, müssen wir nur feststellen, ob es sich um eine durchquerbare Instanz handelt

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

2 Iterator-Schnittstelle

Iteration Das eigentliche Implementierungsprinzip der Geräteschnittstelle ähnelt der Bewegung von Zeigern. Wenn wir eine Klasse schreiben, können wir die entsprechenden fünf Methoden implementieren: key(), current(), next(), rewind() und valid (). Um die iterative Bewegung von Daten zu erreichen, sehen Sie sich den folgenden Code an:

<?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();
    }

## Dieses Ausgabeergebnis:

        0: one
        1: two
        2: three

Wir wissen, nachdem wir dieses Prinzip gesehen haben () -> current() -> valid() ....-> Wir öffnen die Iterator-Schnittstelle und stellen fest, dass sie die Traversable-Schnittstelle implementiert. Als nächstes beweisen wir es:

var_dump($test instanceOf Traversable);

Das Ergebnis gibt true zurück und beweist, dass das Objekt dieser Klasse durchlaufen werden kann.

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

Das Ergebnis ist dasselbe wie das von der while-Schleife implementierte Muster.

3. IteratorAggregate (Aggregation Iterator) Schnittstelle

Die Prinzipien von Aggregatiteratoren und Iteratoren sind die gleichen, aber Der Aggregatiterator hat das Iteratorprinzip bereits implementiert. Sie müssen lediglich eine getIterator()-Methode implementieren, um die Iteration zu implementieren. Weitere Informationen finden Sie im folgenden Code:

<?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);
    }
 }

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

Viele PHPer sind fortgeschritten Es gibt immer einige Probleme und Engpässe. Ich schreibe zu viel Geschäftscode und weiß nicht, wo ich anfangen soll, mich zu verbessern, einschließlich, aber nicht beschränkt auf: verteilte Architektur, hohe Skalierbarkeit , hohe Parallelität, Optimierung der Serverleistung, TP6, Laravel, YII2, Redis, Swoole, Swoft, Kafka, MySQL-Optimierung, Shell-Skripte, Docker, Microservices, Nginx und andere Wissenspunkte. Sie können es kostenlos teilen, wenn Sie der Gruppe beitreten müssen (klicken Sie →) 677079770

ArrayAccess (Array-Zugriff)

Normalerweise sind wir Ich werde dies sehen ['name '] Eine solche Verwendung, aber wir wissen, dass $this ein Objekt ist. Wie kann ich mit der Array-Methode darauf zugreifen? Die Antwort besteht darin, die Datengruppenzugriffsschnittstelle ArrayAccess zu implementieren. Der spezifische Code lautet wie folgt:

<?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 Wenn in unserer Klasse die magischen Methoden „sleep()“ und „wakeup()“ definiert sind, rufen wir bei der Serialisierung () zunächst die magische Methode „sleep()“ auf. Wir geben ein Array zurück, um zu definieren, welche Eigenschaften die Eigenschaften des Objekts haben Wenn wir die Methode unserialize () aufrufen, können wir auch zuerst die magische Methode wakeup () aufrufen, z. B. indem wir den Eigenschaften eines Objekts Werte zuweisen Daher müssen wir die Methoden serialize () und unserialize () gleichzeitig implementieren. Der spezifische Code lautet wie folgt: 🎜>
<?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. Die Abschlussklasse

ist eine Klasse, die zur Darstellung anonymer Funktionen verwendet wird. Diese Klasse hat zwei Hauptmethoden: bindTo() und bind(). Wenn Sie sich den Quellcode ansehen, können Sie feststellen, dass bind() eine statische Methode ist ;

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

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

Anhand des obigen Beispiels können Sie sehen, dass die erste gedruckte Instanz eine Instanz von Closure ist und die zweite die von der anonymen Funktion zurückgegebene Hallo-Welt-Zeichenfolge ausgibt Der nächste Schritt besteht darin, die Methode dieser anonymen Klasse zu verwenden. Der Zweck dieser beiden Methoden besteht darin, anonyme Funktionen an eine Klasse zu binden ()

<?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();

7

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教程

Das obige ist der detaillierte Inhalt vonVertiefendes Verständnis der sieben vordefinierten Schnittstellen in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen