PHP mysqli_result: Use Traversable interface with fetch_object

后端 未结 3 1251
青春惊慌失措
青春惊慌失措 2021-01-13 16:11

the PHP mysqli_result class implements the Traversable interface for some time now. This gives some interesting possibilities like the following piece of code:



        
3条回答
  •  不思量自难忘°
    2021-01-13 16:38

    The (let's call it) traversal-fetch-mode of the mysqli_result can not be influenced. So as it is by default the associative array (column-name as key and it's value as value) like mysqli_result::fetch_assoc() it stays with that.

    So this requires an own Iterator that does the work. So how does a non-foreach iteration of a Mysqli result traditionally look like? Right, the while() loop:

    while($row = $result->fetch_assoc())
    {
       ...
    }
    

    Which reads: while the fetch-method does not return NULL go on. This is a common form to create iteration.

    For iterations of this kind I normally use a FetchingIterator, it is a concrete iterator that turns the PHP specific Iterator interface (rewind, valid, current, key, next) into a more simplified one. That simplified one goes: next on rewind, next on next and valid until NULL - which is pretty much the same as the while loop and can be used for similar working APIs like deprecated mysql or even arrays (compare array_shift etc.). It's also similar to other implementations of iterators in different programming languages, here specifically Java (compare Iterator Design Pattern (Source Making Guide on Design Patterns) article).

    I did outline it rudimentary back last year in my article Some PHP Iterator Fun (Feb 2012) and a much improved, standard implementation of this can be found as FetchingIterator in Iterator Garden which easily allows to do what you want to do.

    Let's see an example application:

    class ObjectFetchIterator extends FetchingIterator
    {
        public function __construct(mysqli_result $result, $class) {
    
            parent::__construct(function() use ($result, $class) {
                return $result->fetch_object($class);
            });
        }
    }
    

    The mysqli_result::fetch_object() method which has been previously within the while(...) has now been moved into the constructor of a FetchingIterator for mysqli results. This is a pretty straight forward implementation of it then. Alternatively, it's also possible to override the protected fetchNext() method but I only note it because it's not needed here.

    The usage example then is pretty straight forward:

    $db       = new mysqli('...');    
    $result   = $db->query('...');    
    $iterator = new ObjectFetchIterator($result, 'myClass');
    
    /* @var $row myClass */
    foreach ($iterator as $row)
    {
       // $row is a myClass now based on fetched values
    }
    

    As this example shows, there is no need to use PDO for that and it sounds like a pretty lazy excuse: Changing the whole database layer only for this little detail? No! The opposite is the case: Using an iterator here in the foreach allows you to de-couple your code from the concrete database access library to the generic type (as it was possible with arrays earlier too, however arrays are by far not that distinct as object types).

    Hope this helps even the answer comes a little late. Just came to my attention this wasn't really answered so far.

提交回复
热议问题