미리 정의된 인터페이스에 대한 심층적인 이해
시나리오: 일반적인 작업에서는 비즈니스 모듈을 작성하고 이러한 인터페이스를 거의 구현하지 않지만 프레임워크에서는 많이 사용됩니다.
1. 순회 인터페이스
이 인터페이스는 클래스에서 직접 구현할 수 없습니다. 순회 인터페이스를 구현하기 위해 일반 클래스를 직접 작성하면 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를 사용하여 클래스를 탐색할 수 있는지 여부를 확인하려면 해당 클래스가 탐색 가능한 인스턴스인지 여부만 확인하면 됩니다
class Test { } $test = new Test; var_dump($test instanceOf Traversable);
2. 반복자 인터페이스
반복자 인터페이스의 실제 구현 원리는 포인터 이동과 유사합니다. 클래스를 작성할 때 해당 5가지 메서드(key(), current(), next(), rewind(), valid()는 데이터의 반복 이동을 실현할 수 있습니다. 자세한 내용은 다음 코드를 참조하세요.
<?php class Test implements Iterator { private $key; private $val = [ 'one', 'two', 'three', ]; 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 . ':' . $test->current() . PHP_EOL; $test->next(); }
## 출력 결과: > -> valid()-> key() ....-> valid();
좋습니다. 위 내용을 이해한 후 Iterator 인터페이스를 열고 Traversable 인터페이스를 구현합니다. 증명하세요:
0: one 1: two 2: three
결과는 true를 반환하며, 이는 이 클래스의 객체가 탐색될 수 있음을 증명합니다.
var_dump($test instanceOf Traversable);
결과는 while 루프에서 구현한 패턴과 동일합니다.
3. IteratorAggregate(집계 반복자) 인터페이스
집합 반복자와 반복자의 원리는 동일합니다. 단, 집합 반복자는 이미 반복자 원칙을 구현했기 때문에 getIterator( ) 메서드만 구현하면 됩니다. 반복을 수행하려면 다음 코드에서 자세한 내용을 확인하세요.
foreach ($test as $key => $value){ echo $test->key . ':' . $test->current() . PHP_EOL; }
많은 PHP 사용자는 비즈니스 코드를 너무 많이 작성하고 어디로 가야할지 모릅니다. 개선을 시작했습니다. 분산 아키텍처, 높은 확장성, 고성능, 높은 동시성, 서버 성능 튜닝, TP6, laravel, YII2, Redis, Swoole, Swoft, Kafka, Mysql 최적화, 쉘을 포함하되 이에 국한되지는 않습니다. script, Docker, 마이크로서비스, Nginx 및 기타 고급 지식 포인트는 모든 사람과 무료로 공유할 수 있습니다. 필요한 경우 그룹에 가입하세요(→ 클릭) 677079770
4. 일반적으로 ArrayAccess 인터페이스다음으로 살펴보겠습니다. this ['name']을 사용하지만 $this가 객체라는 것을 알고 있는데 배열을 사용하여 어떻게 액세스할 수 있나요? 대답은 데이터 그룹 액세스 인터페이스 ArrayAccess를 구현하는 것입니다. 구체적인 코드는 다음과 같습니다
<?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() . ' : ' . $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 . ' : ' . $value . PHP_EOL; } 接下来,我们看到是对对象进行迭代,这个时候我们是否可以数组进行迭代呢? class Test implements IteratorAggregate { public $data; public function __construct() { $this->data = [''one' => 1 , 'two' => 2]; } public function getIterator() { return new AraayIterator($this->data); } } 同理实现的方式跟对对象进行迭代是一样的。
5. 직렬화 가능 인터페이스
일반적으로 우리 클래스에 정의된 매직 메소드가 있는 경우 sleep(), wakeup( ) , 직렬화()할 때 먼저 sleep()의 마법 메서드를 호출하여 객체의 어떤 속성이 직렬화되는지 정의하는 배열을 반환합니다. 같은 방식으로 deserialization unserialize() 메서드인 wakeup()을 호출합니다. 객체의 속성에 값을 할당하는 등의 방법으로 초기화할 수도 있지만 클래스가 직렬화 인터페이스를 구현하는 경우에는 serialize() 메서드를 구현해야 합니다. 두 가지 매직 메소드인 sleep() 및 wakeup()은 더 이상 동시에 지원되지 않습니다. 구체적인 코드는 다음과 같습니다.
<?php class Test implements ArrayAccess { public $container; public function __construct() { $this->container = [ 'one' => 1, 'two' => 2, 'three' => 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['one'])); var_dump($test['two']); unset($test['two']); var_dump(isset($test['two'])); $test['two'] = 22; var_dump($test['two']); $test[] = 4; var_dump($test); var_dump($test[0]); 当然我们也有经典的一个做法就是把对象的属性当做数组来访问 class Test implements ArrayAccess { public $name; public function __construct() { $this->name = 'gabe'; } 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['name'])); var_dump($test['name']); var_dump($test['age']); $test[1] = '22'; var_dump($test); unset($test['name']); var_dump(isset($test['name'])); var_dump($test); $test[] = 'hello world'; var_dump($test);
6. 클로저 클래스
는 익명 함수를 나타내는 데 사용됩니다. 모든 익명 함수는 실제로 Closure 클래스의 인스턴스를 반환합니다. 이 클래스에는 두 가지 주요 메서드인 바인딩()과 바인딩()이 있습니다. 소스 코드를 보면 두 메서드의 목표가 동일하다는 것을 알 수 있습니다. 바인딩( )은 정적 메소드이며 구체적인 사용법은 다음과 같습니다.
<?php class Test { public $name; public $age; public function __construct() { $this->name = 'gabe'; $this->age = 25; } public function __wakeup() { var_dump(__METHOD__); $this->age++; } public function __sleep() { var_dump(__METHOD__); return ['name']; } } $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 = 'gabe'; $this->age = 25; } public function __wakeup() { var_dump(__METHOD__); $this->age++; } public function __sleep() { var_dump(__METHOD__); return ['name']; } 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));
위의 예를 통해 인쇄된 첫 번째 것은 Closure의 인스턴스이고 두 번째는 반환된 hello world 문자열을 인쇄하는 것을 볼 수 있습니다. 다음은 이 익명 클래스를 사용하는 방법입니다. 이 두 가지 방법의 목적은 익명 함수를 클래스에 바인딩하는 것입니다.
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 . ': ' . $value . PHP_EOL; } echo 'memory: ' . memory_get_usage() . ' time: '. (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 . ': ' . $value . PHP_EOL; } echo 'memory: ' . memory_get_usage() . ' time: '. (microtime(true) - $start_time);
输出:
memory: 6680312 time: 0.10804104804993
更多相关php知识,请访问php教程!
위 내용은 PHP의 사전 정의된 7가지 인터페이스에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!