Movatterモバイル変換


[0]ホーム

URL:


update page now
    マジックメソッド »
    « オーバーロード

    オブジェクトの反復処理

    PHP は、たとえばforeach 命令などによる反復処理を可能とするように、 オブジェクトを定義する手段を提供します。 デフォルトで、 全てのアクセス権限がある プロパティは、反復処理に使用することができます。

    例1 単純なオブジェクトの反復の例

    <?php
    classMyClass
    {
    public
    $var1='value 1';
    public
    $var2='value 2';
    public
    $var3='value 3';

    protected
    $protected='protected var';
    private
    $private='private var';

    function
    iterateVisible() {
    echo
    "MyClass::iterateVisible:\n";
    foreach (
    $thisas$key=>$value) {
    print
    "$key =>$value\n";
    }
    }
    }

    $class= newMyClass();

    foreach(
    $classas$key=>$value) {
    print
    "$key =>$value\n";
    }
    echo
    "\n";


    $class->iterateVisible();

    ?>

    上の例の出力は以下となります。

    var1 => value 1var2 => value 2var3 => value 3MyClass::iterateVisible:var1 => value 1var2 => value 2var3 => value 3protected => protected varprivate => private var

    出力からわかるように、foreach による反復処理がすべてのアクセス権がある プロパティについて行われています。

    参考

    Found A Problem?

    Learn How To Improve This PageSubmit a Pull RequestReport a Bug
    add a note

    User Contributed Notes17 notes

    php dot net dot nsp at cvogt dot org
    13 years ago
    there is still an open bug about using current() etc. with iteratorshttps://bugs.php.net/bug.php?id=49369
    wavetrex A(nospam)T gmail DOT com
    17 years ago
    By reading the posts below I wondered if it really is impossible to make an ArrayAccess implementation really behave like a true array ( by being multi level )Seems like it's not impossible. Not very preety but usable<?phpclassArrayAccessImplimplementsArrayAccess{  private$data= array();  public functionoffsetUnset($index) {}  public functionoffsetSet($index,$value) {//    echo ("SET: ".$index."<br>");if(isset($data[$index])) {        unset($data[$index]);    }$u= &$this->data[$index];    if(is_array($value)) {$u= newArrayAccessImpl();        foreach($valueas$idx=>$e)$u[$idx]=$e;    } else$u=$value;  }  public functionoffsetGet($index) {//    echo ("GET: ".$index."<br>");if(!isset($this->data[$index]))$this->data[$index]=newArrayAccessImpl();        return$this->data[$index];  }  public functionoffsetExists($index) {//    echo ("EXISTS: ".$index."<br>");if(isset($this->data[$index])) {        if($this->data[$index] instanceofArrayAccessImpl) {            if(count($this->data[$index]->data)>0)                returntrue;            else                returnfalse;        } else            returntrue;    } else        returnfalse;  }}echo"ArrayAccess implementation that behaves like a multi-level array<hr />";$data= newArrayAccessImpl();$data['string']="Just a simple string";$data['number']=33;$data['array']['another_string']="Alpha";$data['array']['some_object']=newstdClass();$data['array']['another_array']['x']['y']="LOL @ Whoever said it can't be done !";$data['blank_array']=array();echo"'array' Isset? ";print_r(isset($data['array'])); echo"<hr />";echo"<pre>";print_r($data['array']['non_existent']); echo"</pre>If attempting to read an offset that doesn't exist it returns a blank object! Use isset() to check if it exists!<br>";echo"'non_existent' Isset? ";print_r(isset($data['array']['non_existent'])); echo"<br />";echo"<pre>";print_r($data['blank_array']); echo"</pre>A blank array unfortunately returns similar results :(<br />";echo"'blank_array' Isset? ";print_r(isset($data['blank_array'])); echo"<hr />";echo"<pre>";print_r($data); echo"</pre> (non_existent remains in the structure. If someone can help to solve this I'll appreciate it)<hr />";echo"Display some value that exists: ".$data['array']['another_string'];?>(in the two links mentioned below by artur at jedlinski... they say you can't use references, so I didn't used them.My implementation uses recursive objects)If anyone finds a better (cleaner) sollution, please e-mail me.Thanks,Wave.
    hlegius at gmail dot com
    17 years ago
    Iterator interface usign key() next() rewind() is MORE slow than extends ArrayIterator with ArrayIterator::next(), ArrayIterator::rewind(), etc.,
    strrev('ed.relpmeur@ekneos');
    20 years ago
    Use the SPL ArrayAccess interface to call an object as array:http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html
    chad 0x40 herballure 0x2e com
    19 years ago
    The example code given for valid() will break if the array contains a FALSE value. This code prints out a single "bool(true)" and exits the loop when it gets to the FALSE:<?php$A= array(TRUE,FALSE,TRUE,TRUE);while(current($A) !==FALSE) {var_dump(current($A));next($A);}?>Instead, the key() function should be used, since it returns NULL only at the end of the array. This code displays all four elements and then exits:<?php$A= array(TRUE,FALSE,TRUE,TRUE);while(!is_null(key($A))) {var_dump(current($A));next($A);}?>
    markushe at web dot de
    20 years ago
    Just something i noticed:It seems, that when you are implementing the interface Iterator, yout method key() has to return a string or integer.I was trying to return a object an got this error:Illegal type returned from MyClass::key()
    elias at need dot spam
    20 years ago
    The MyIterator::valid() method above ist bad, because itbreaks on entries with 0 or empty strings, use key() instead:<?phppublic functionvalid(){    return !is_null(key($this->var));}?>read about current() drawbacks:http://php.net/current
    just_somedood at yahoo dot com
    20 years ago
    To clarify on php at moechofe's post, you CAN use the SPL to overide the array operator for a class.  This, with the new features of object, and autoloading (among a buch of other things) has me completely sold on PHP5.  You can also find this information on the SPL portion of the manual, but I'll post it here as well so it isn't passed up.  The below Collection class will let you use the class as an array, while also using the foreach iterator:<?phpclassCollectionimplementsArrayAccess,IteratorAggregate{    public$objectArray= Array();//**these are the required iterator functionsfunctionoffsetExists($offset)    {                  if(isset($this->objectArray[$offset]))  returnTRUE;        else returnFALSE;              }            function &offsetGet($offset)    {           if ($this->offsetExists($offset))  return$this->objectArray[$offset];        else return (false);    }        functionoffsetSet($offset,$value)    {                  if ($offset)$this->objectArray[$offset] =$value;        else$this->objectArray[] =$value;    }        functionoffsetUnset($offset)    {        unset ($this->objectArray[$offset]);    }        function &getIterator()    {        return newArrayIterator($this->objectArray);    }//**end required iterator functionspublic functiondoSomething()    {        echo"I'm doing something";    }}?>I LOVE the new SPL stuff in PHP!  An example of usage is below:<?phpclassContact{    protected$name=NULL;    public functionset_name($name)    {$this->name=$name;    }        public functionget_name()    {        return ($this->name);    }}$bob= newCollection();$bob->doSomething();$bob[] = newContact();$bob[5] = newContact();$bob[0]->set_name("Superman");$bob[5]->set_name("a name of a guy");foreach ($bobas$aContact){     echo$aContact->get_name() ."\r\n";}?>Would work just fine.  This makes code so much simpler and easy to follow, it's great.  This is exactly the direction I had hoped PHP5 was going!
    knj at aider dot dk
    20 years ago
    if you in a string define classes that implements IteratorAggregate.you cant use the default;<?...public function getIterator() {       return new MyIterator(\\$this-><What ever>);}..?>at least not if you want to use eval(<The string>).You have to use:<?...public function getIterator() {      \\$arrayObj=new ArrayObject(\\$this-><What ever>);      return \\$arrayObj->getIterator();}...?>
    mike at eastghost dot com
    2 years ago
    The days of lovely care-to-the-wind typecasting are coming to close.  Finding this devilish bug took us entirely too long.PHP-8.2.1 was throwing errors seemingly uncaught (they were eventually seen amassing in  / var / log / apache / DOMAIN-ssl-err.log  ) due to mismatch between return types of the necessary interface methods in our 'implements \Iterator' class (which had worked fine for many years, until our leap up to 8.2.1) versus the interface methods required by PHP.Particularly:next()=====ours:public function next() {...}PHP-8.2.1'spublic function next() : void {...}valid()======ours:public function valid() {...}PHP-8.2.1's:public function valid() : bool {...}key()====ours:public function key() {...}PHP-8.2.1's:public function key() : mixed {...}rewind()========ours:public function rewind() {...}PHP-8.2.1's:public function rewind() : void {...}current()=======ours:public function current() {...}PHP-8.2.1's:public function current() : mixed {...}We added the missing / now all-important return types to our function/method declarations and everything instantly worked again.This extreme stringency is not made clear enough, IMHO, in the Iterator manual page.
    baldurien at bbnwn dot eu
    19 years ago
    Beware of how works iterator in PHP if you come from Java!In Java, iterator works like this :<?phpinterfaceIterator<O> {boolean hasNext();O next();void remove();}?>But in php, the interface is this (I kept the generics and type because it's easier to understand)<?phpinterfaceIterator<O> {boolean valid();mixed key();O current();void next();void previous();void rewind();}?>1. valid() is more or less the equivalent of hasNext()2. next() is not the equivalent of java next(). It returns nothing, while Java next() method return the next object, and move to next object in Collections. PHP's next() method will simply move forward.Here is a sample with an array, first in java, then in php :<?phpclassArrayIterator<O> implementsIterator<O> {  private finalO[] array;  privateint index=0;  publicArrayIterator(O[] array) {this.array = array;  }    publicboolean hasNext() {    returnindex< array.length;  }    publicO next() {     if ( !hasNext())        throw newNoSuchElementException('at end of array');     return array[index++];  }  publicvoid remove() {    throw newUnsupportedOperationException('remove() not supported in array');  }}?> And here is the same in php (using the appropriate function) :<?php/** * Since the array is not mutable, it should use an internal  * index over the number of elements for the previous/next  * validation. */classArrayIteratorimplementsIterator{  private$array;  public function__construct($array) {    if ( !is_array($array))       throw newIllegalArgumentException('argument 0 is not an array');$this->array= array;$this->rewind();  }  public functionvalid() {    returncurrent($this->array) !==false;// that's the bad method (should use arrays_keys, + index)}  public functionkey() {     returnkey($this->array);  }  public functioncurrent() {    returncurrent($this->array);  }  public functionnext() {    if ($this->valid())       throw newNoSuchElementException('at end of array');next($this->array);  }  public functionprevious()  {// fails if current() = first item of arrayprevious($this->array);  }  public functionrewind() {reset($this->array);  }}?>The difference is notable : don't expect next() to return something like in Java, instead use current(). This also means that you have to prefetch your collection to set the current() object. For instance, if you try to make a Directory iterator (like the one provided by PECL), rewind should invoke next() to set the first element and so on. (and the constructor should call rewind())Also, another difference :<?phpclassArrayIterable<O> implementsIterable<O> {  private finalO[] array;  publicArrayIterable(O[] array) {this.array = array;  }    publicIterator<O>iterator() {     return newArrayIterator(array);  }}?>When using an Iterable, in Java 1.5, you may do such loops :<?phpfor (String s: newArrayIterable<String>(newString[] {"a","b"})) {  ...}?>Which is the same as :<?phpIterator<String>it= newArrayIterable<String>(newString[] {"a","b"});while (it.hasNext()) {String s=it.next();  ...}?>While in PHP it's not the case :<?phpforeach ($iteratoras$current) {  ...}?>Is the same as :<?phpfor ($iterator->rewind();$iterator->valid();$iterator->next()) {$current=$iterator->current();  ...}?>(I think we may also use IteratorAggregate to do it like with Iterable).Take that in mind if you come from Java.I hope this explanation is not too long...
    rune at zedeler dot dk
    18 years ago
    The iterator template from knj at aider dot dk does not yield correct results.If you do<?reset($a);next($a);echo current($a);?>where $a is defined over the suggested template, then the first element will be output, not the second, as expected.
    artur at jedlinski dot pl
    18 years ago
    One should be aware that ArrayAccess functionality described by "just_somedood at yahoo dot com" below is currently broken and thus it's pretty unusable.Read following links to find more:http://bugs.php.net/bug.php?id=34783http://bugs.php.net/bug.php?id=32983
    celsowm
    6 years ago
    I've created a dinamic version of grzeniufication code to allow un-, serialize more than one property:<?phpclassPersonimplements\Serializable{    public$id;    public$name;    public$birthDate;    public$surname;    public functionserialize() {        returnserialize((array)$this);    }    public functionunserialize($serialized):void{        foreach (unserialize($serialized) as$p=>$v) {$this->{$p} =$v;        }    }}
    phpnet at nicecupofteaandasitdown dot com
    20 years ago
    You should be prepared for your iterator's current method to be called before its next method is ever called. This certainly happens in a foreach loop. If your means of finding the next item is expensive you might want to use something like thisprivate $item;        function next() {    $this->item = &$this->getNextItem();    return $this->item;}    public function current() {     if(!isset($this->item)) $this->next();    return $this->item;}
    doctorrock83_at_gmail.com
    18 years ago
    Please remember that actually the only PHP iterating structure that uses Iterator is foreach().Any each() or list() applied to an Object implementing iterator will not provide the expected result
    PrzemekG_ at poczta dot onet dot pl
    20 years ago
    If you want to do someting like this:<?phpforeach($MyObjectas$key=> &$value)$value='new '.$value;?>you must return values by reference in your iterator object:<?phpclassMyObjectimplementsIterator{/* ...... other iterator functions ...... *//* return by reference */public function &current(){   return$something;}?>This won't change values:<?phpforeach($MyObjectas$key=>$value)$value='new '.$value;?>This will change values:<?phpforeach($MyObjectas$key=> &$value)$value='new '.$value;?>I think this should be written somewhere in the documentations, but I couldn't find it.
    add a note
    To Top
    and to navigate •Enter to select •Esc to close •/ to open
    PressEnter without selection to search using Google

    [8]ページ先頭

    ©2009-2025 Movatter.jp