Hogyan írhatunk saját iterálható objektumokat PHP-ben – CloudSavvy IT

Avatar Gadam | 2021.02.20.

[ad_1]

PHP logó

A PHP lehetővé teszi iterálható objektumok létrehozását. Ezek a hurkokon belül használhatók skaláris tömbök helyett. Az iterable-t általában objektum-gyűjteményként használják. Lehetővé teszik az objektum gépelését, miközben megtartják a looping támogatását.

Egyszerű iteráció

A PHP tömbjének ismétléséhez használja a foreach hurok:

foreach (["1", "2", "3"] as $i) {
    echo ($i . " ");
}

Ez a példa kibocsátaná 1 2 3.

Iterálhat egy objektum felett is:

$cls = new StdClass();
$cls -> foo = "bar";
foreach ($cls as $i) {
    echo $i;
}

Ez a példa kibocsátaná bar.

A gyűjtési probléma

Köztulajdonú alaposztályok számára síkság foreach jól működik. Vegyünk egy másik osztályt:

class UserCollection {
 
    protected array $items = [];
 
    public function add(UserDomain $user) : void {
        $this -> items[] = $user;
    }
 
    public function containsAnAdmin() : bool {
        return (count(array_filter(
            $this -> items,
            fn (UserDomain $i) : bool => $i -> isAdmin()
        )) > 0);
    }
 
}

Ez az osztály a UserDomain példányok. Mivel a PHP nem támogatja a tipizált tömböket, ehhez hasonló osztályokra van szükség, ha olyan tömböt szeretne begépelni, amely csak egy típusú értéket képes tárolni. A gyűjtemények segítenek létrehozni például a containsWithAdmin, amelyek megkönnyítik a tömbökkel való természetes interakciót.

Sajnos, ha megpróbáljuk megismételni ezt a gyűjteményt, az nem fogja elérni a kívánt eredményt. Ideális esetben az iterációnak a $items tömb, nem maga az osztály.

Az Iterator megvalósítása

Természetes iteráció hozzáadható a Iterator felület. Megvalósítással Iterator, meghatározhatja a PHP viselkedését, amikor az osztály példányait használja foreach.

Iterator öt módszerrel rendelkezik, amelyek végrehajtásához szüksége lesz:

  • current() : mixed – Szerezze be az elemet az iteráció jelenlegi helyzetében.
  • key() : scalar – Szerezze be a kulcsot az iteráció jelenlegi helyzetében.
  • next() : void – Lépjen az iteráció következő pozíciójára.
  • rewind() : void – Tekerje vissza a pozíciót az iteráció kezdetéig.
  • valid() : bool – Tudja meg, hogy az aktuális pozíciónak van-e értéke.

Ezek a módszerek eleinte zavaróak lehetnek. Ezek megvalósítása azonban egyszerű – meghatározza, hogy mit kell tennie az a minden szakaszában foreach végrehajtás.

Minden alkalommal, amikor az objektumot használjuk foreach, rewind() hívni fogják. A valid() metódust hívják meg a következőnek, tájékoztatva a PHP-t arról, hogy van-e érték az aktuális pozíción. Ha van, current() és key() hívják, hogy az értéket és a kulcsot megkapják abban a helyzetben. Végül a next() metódust hívnak a pozíciómutató előrehozására. A hurok visszatér a híváshoz valid() hogy van-e más elem.

Itt található a Iterator:

class DemoIterator {
 
    protected int $position = 0;
 
    protected array $items = ["cloud", "savvy"];
 
    public function rewind() : void {
        echo "Rewinding";
        $this -> position = 0;
    }
 
    public function current() : string {
        echo "Current";
        return $this -> items[$this -> position];
    }
 
    public function key() : int {
        echo "Key";
        return $this -> position;
    }
 
    public function next() : void {
        echo "Next";
        ++$this -> position;
    }
 
    public function valid() : void {
        echo "Valid";
        return isset($this -> items[$this -> position]);
    }
 
}

Íme, mi történne iteráláskor DemoIterator:

$i = new DemoIterator();
foreach ($i as $key => $value) {
    echo "$key $value";
}
 
// EMITS:
// 
// Rewind
// Valid Current Key
// 0 cloud
// Next
// 
// Valid Current Key
// 1 savvy
// Next
// 
// Valid

Az iterátorának nyilvántartást kell vezetnie a hurok helyzetéről, ellenőriznie kell, hogy van-e elem az aktuális hurok helyzetében (via valid()), és adja vissza a kulcsot és az értéket az aktuális helyzetben.

A PHP nem próbálja meg elérni a kulcsot vagy értéket, ha a hurok pozíciója érvénytelen. Visszatérve false tól től valid() azonnal megszünteti a foreach hurok. Ez általában akkor lesz, amikor a tömb végére ér.

IteratorAggregate

Az iterátorok írása gyorsan ismétlődik. A legtöbben a fenti receptet követik pontosan. IteratorAggregate egy felület, amely segít iterálható objektumok gyors létrehozásában.

Végezze el a getIterator() módszer és adja vissza a Traversable (az alap interfész Iterator). Iterátorként fogja használni, amikor az objektumot együtt használják foreach. Ez általában a legegyszerűbb módja az iteráció hozzáadásának egy gyűjtemény osztályhoz:

class UserCollection implements IteratorAggregate {
 
    protected array $items = [];
 
    public function add(UserDomain $User) : void {
        $this -> items[] = $user;
    }
 
    public function getIterator() : Traversable {
        return new ArrayIterator($this -> items);
    }
 
}
 
$users = new UserCollection();
$users -> add(new UserDomain("James"));
$users -> add(new UserDomain("Demo"));
 
foreach ($users as $user) {
    echo $user -> Name;
}

A gyűjteményekkel való munka során általában három kódsorra van szükség az iteráció beállításához! An ArrayIterator mint a Traversable. Ez egy olyan osztály, amely automatikusan létrehoz egy Iterator egy tömbből. Most az objektumon belüli logikai értékek felett iterálhat, az objektum közvetlen tulajdonságai helyett.

Előre épített PHP iterátorok használata

Ha komplex logikával rendelkezik, meg kell írnia a saját iterátorait. Ritkán kell elölről kezdeni, ahogy a PHP szállítja több fejlett iterátor az SPL nyújtotta.

A beépített osztályok tartalmazzák DirectoryIterator, FilesystemIterator, GlobIterator és különféle rekurzív iterátorok. Íme néhány leghasznosabb általános iterátor.

LimitIterator

A LimitIterator lehetővé teszi egy tömb egy részhalmazának ismétlését. Nem kell először felosztania a tömböt, vagy manuálisan kell nyomon követnie a belsejében lévő pozíciót foreach.

$arr = new ArrayIterator(["a", "b", "c", "d"]);
foreach (new LimitIterator($arr, 0, 2) as $val) {
    echo $val;
}

Ez a példa kibocsátaná a b. Vegye figyelembe, hogy LimitIterator elfogad egy másikat Iterator, nem tömb. A példa felhasználja ArrayIterator, a beépített osztály, amely egy Iterator tömbből.

InfiniteIterator

InfiniteIterator soha nem szünteti meg a ciklust, ezért meg kell break belőle kézzel. Ellenkező esetben az iterátor automatikusan visszaáll a tömb elejére, amikor a végére ér.

Ez az iterátor különösen hasznos, ha időalapú értékekkel dolgozik. Itt van egy egyszerű módszer a hároméves naptár összeállítására, amely a LimitIterator fent leírt:

$months = [
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
];
$infinite = new InfiniteIterator(new ArrayIterator($months));
foreach (new LimitIterator($infinite, 0, 36) as $month) {
    echo $month;
}

Ez három év hónapokat bocsát ki.

FilterIterator

FilterIterator egy absztrakt osztály, amelyet ki kell terjesztenie. Végezze el a accept módszer a nem kívánt értékek kiszűrésére, amelyeket ki kell hagyni az iteráció során.

class DemoFilterIterator extends FilterIterator {
 
    public function __construct() {
        parent::__construct(new ArrayIterator([1, 10, 4, 6, 3]));
    }
 
    public function accept() {
        return ($this -> getInnerIterator() -> current() < 5);
    }
 
}
 
$demo = new DemoFilterIterator();
 
foreach ($demo as $val) {
    echo $val;
}

Ez a példa kibocsátaná 1 4 3.

Az 5-nél magasabb tömbértékeket kiszűrjük, és nem jelennek meg a foreach.

Az „iterálható” típus

Néha írhat egy általános függvényt, amely a-t használja foreach ciklus, de nem tud semmit azokról az értékekről, amelyeken iterálni fog. Ilyen például egy absztrakt hibakezelő, amely egyszerűen kiírja a kapott értékeket.

Gépelhet iterable ezekben a forgatókönyvekben. Ez egy ál-típus, amely elfogadja az egyiket is array vagy bármilyen objektum megvalósítása Traversable:

function handleBadValues(iterable $values) : void {
    foreach ($values as $value) {
        var_dump($value);
    }
}

A iterable típus annyira homályos, hogy alaposan át kell gondolni, mielőtt felhasználná. Mindazonáltal hasznos lehet egy utolsó lehetőségként, ha garantálnia kell, hogy egy bemeneti érték működni fog foreach.

Következtetés

Az iterátorok használata segít a modulárisabb tiszta kód megírásában. Az objektumok tömbjeire ható módszereket áthelyezheti dedikált gyűjtési osztályokba. Ezeket aztán egyedileg lehet gépírni, miközben teljesen kompatibilisek maradnak foreach.

Az iterációs támogatás hozzáadása legtöbbször megvalósítással érhető el IteratorAggregate és visszatér egy ArrayIterator konfigurálva a gyűjtemény elemeivel. A PHP egyéb iterátortípusai, amelyeket általában nem használnak a fejlesztők, jelentősen leegyszerűsíthetik a specifikusabb ciklusokat. Összetett logikai viselkedést kínálnak anélkül, hogy kézi mutatókövetést igényelnének a foreach nyilatkozat.

[ad_2]
Source link


Written by Gadam