PHP의 반복자(실용 가이드)
$users = [new User(), new User()];
Iterator를 사용할 기회를 놓쳤습니다.
왜 이터레이터인가?
컬렉션은 이전에 명명되지 않은 배열을 구성하는 멋진 방법입니다. 반복자를 사용해야 하는 몇 가지 이유가 있습니다. 동작에 대한 이유 중 하나는 다음, 현재, 유효 등과 같은 표준 호출에서 정확한 동작을 지정할 수 있습니다. 다른 이유는 컬렉션에 특정 유형의 객체만 포함되도록 하기를 원할 수 있습니다.
알 수 없는 값 유형의 배열을 사용하여 발생하는 문제를 이해합니다.
PHP 세계에서 매우 일반적인 배열은 모든 종류의 데이터를 여러 중첩 형식의 여러 차원으로 저장하는 데 사용됩니다. 배열은 개발자에게 무한한 유연성을 제공했지만 그 때문에 매우 사악해졌습니다.
예시:
public function getUsers(): array
{
/**
here happen something which gets users from database
....
**/
return $userArray;
}
public function setUsersToActiveState()
{
$users = $this->getUsers();
/** @var User $param */
foreach ($users as $user) {
if(!$user->getActiveStatus()) {
$user->setActiveStatus(true);
}
}
}
즉시 두 가지 문제가 발생했습니다.
사용자 $param */위의 foreach, phpStorm에서 작동하고 다른 IDE에서 추측)
해결책
// Create a collection which accepts only Users
class UsersCollection implements \IteratorAggregate
{
/** @var array */
private $users = [];
public function getIterator() : UserIterator
{
return new UserIterator($this);
}
public function getUser($position)
{
if (isset($this->users[$position])) {
return $this->users[$position];
}
return null;
}
public function count() : int
{
return count($this->users);
}
public function addUser(User $users)
{
$this->users[] = $users;
}
}
// Create an Iterator for User
class UserIterator implements \Iterator
{
/** @var int */
private $position = 0;
/** @var UsersCollection */
private $userCollection;
public function __construct(UsersCollection $userCollection)
{
$this->userCollection = $userCollection;
}
public function current() : User
{
return $this->userCollection->getUser($this->position);
}
public function next()
{
$this->position++;
}
public function key() : int
{
return $this->position;
}
public function valid() : bool
{
return !is_null($this->userCollection->getUser($this->position));
}
public function rewind()
{
$this->position = 0;
}
}
테스트
물론 컬렉션과 반복자가 매력처럼 작동하는지 확인하는 테스트가 있습니다. 이 예제에서는 PHPUnit 프레임워크용 구문을 사용합니다.
class UsersCollectionTest extends TestCase
{
/**
* @covers UsersCollection
*/
public function testUsersCollectionShouldReturnNullForNotExistingUserPosition()
{
$usersCollection = new UsersCollection();
$this->assertEquals(null, $usersCollection->getUser(1));
}
/**
* @covers UsersCollection
*/
public function testEmptyUsersCollection()
{
$usersCollection = new UsersCollection();
$this->assertEquals(new UserIterator($usersCollection), $usersCollection->getIterator());
$this->assertEquals(0, $usersCollection->count());
}
/**
* @covers UsersCollection
*/
public function testUsersCollectionWithUserElements()
{
$usersCollection = new UsersCollection();
$usersCollection->addUser($this->getUserMock());
$usersCollection->addUser($this->getUserMock());
$this->assertEquals(new UserIterator($usersCollection), $usersCollection->getIterator());
$this->assertEquals($this->getUserMock(), $usersCollection->getUser(1));
$this->assertEquals(2, $usersCollection->count());
}
private function getUserMock()
{
// returns the mock of User class
}
}
class UserIteratorTest extends MockClass
{
/**
* @covers UserIterator
*/
public function testCurrent()
{
$iterator = $this->getIterator();
$current = $iterator->current();
$this->assertEquals($this->getUserMock(), $current);
}
/**
* @covers UserIterator
*/
public function testNext()
{
$iterator = $this->getIterator();
$iterator->next();
$this->assertEquals(1, $iterator->key());
}
/**
* @covers UserIterator
*/
public function testKey()
{
$iterator = $this->getIterator();
$iterator->next();
$iterator->next();
$this->assertEquals(2, $iterator->key());
}
/**
* @covers UserIterator
*/
public function testValidIfItemInvalid()
{
$iterator = $this->getIterator();
$iterator->next();
$iterator->next();
$iterator->next();
$this->assertEquals(false, $iterator->valid());
}
/**
* @covers UserIterator
*/
public function testValidIfItemIsValid()
{
$iterator = $this->getIterator();
$iterator->next();
$this->assertEquals(true, $iterator->valid());
}
/**
* @covers UserIterator
*/
public function testRewind()
{
$iterator = $this->getIterator();
$iterator->rewind();
$this->assertEquals(0, $iterator->key());
}
private function getIterator() : UserIterator
{
return new UserIterator($this->getCollection());
}
private function getCollection() : UsersCollection
{
$userItems[] = $this->getUserMock();
$userItems[] = $this->getUserMock();
$usersCollection = new UsersCollection();
foreach ($userItems as $user) {
$usersCollection->addUser($user);
}
return $usersCollection;
}
private function getUserMock()
{
// returns the mock of User class
}
}
용법
public function getUsers(): UsersCollection
{
$userCollection = new UsersCollection();
/**
here happen something which gets users from database
....
**/
foreach ($whatIGetFromDatabase as $user) {
$userCollection->addUser($user);
}
return $userCollection;
}
public fucntion setUsersToActiveState()
{
$users = $this->getUsers();
foreach ($users as $user) {
if(!$user->getActiveStatus()) {
$user->setActiveStatus(true);
}
}
}
보시다시피 setUsersToActiveState는 동일하게 유지되므로 IDE 또는 동료에게 $users 변수 유형을 지정할 필요가 없습니다.
기능 확장
이 두 개체를 재사용하고 대부분의 필요에 맞게 변수 이름을 변경할 수 있습니다. 그러나 더 복잡한 기능을 원하면 반복자 또는 컬렉션에 자유롭게 추가하십시오.
예 1
예를 들어 userCollection이 18세 이상의 사용자만 허용한다고 가정해 보겠습니다. 구현은 addUser 메서드의 UsersCollection 클래스에서 발생합니다.
public function addUser(User $users)
{
if ($user->getAge() > 18) {
$this->users[] = $users;
}
}
예 2
대량 사용자를 추가해야 합니다. 그런 다음 추가 메서드 addUsers를 사용하여 userCollection을 확장하면 다음과 같이 표시될 수 있습니다.
public function addUsers(array $users)
{
foreach($users as $user) {
$this->addUser(User $users);
}
}
메모
나는 대답하는이 훌륭한 기사를 찾았습니다. 왜 일반적으로 배열을 반환하는 것이 나쁜 생각인지, 나는 더 이상 동의 할 수 없습니다
이 주제에
연관 배열을 반환하지 마십시오!
Aleksi Kauppila ・ 8월 15 '18 ・ 3 분 읽기
#php
#oop
#beginners
Reference
이 문제에 관하여(PHP의 반복자(실용 가이드)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/damnjan/iterator-in-php-a-practical-guide-2k59텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)