使用CachingIterator将PHP数组转换为字符串转换通知

I have done some searching on Stackoverflow already on this topic, however as far as I can tell, I am not treating an array as a string ?

The message I am getting is :

Array to string conversion in X on line 42

Line 42 of my code is the opening of a foreach loop :

foreach ($collection as $element) {

Variable $collection is a caching iterator that is based on database output:

$collection=new \CachingIterator(new \ArrayIterator($this->dbData));

If I print_r() on $this->dbData, I certainly get an array:

Array
(
    [0] => Array
        (
            [c_id] => A
 )

    [1] => Array
        (
            [c_id] => B
)

So, in summary:

  • We have a confirmed output of an array
  • We know that ArrayIterator() expects an array as argument
  • We know that CachingIterator() expects an Iterator as argument
  • We know that foreach() can loop over an Iterator

TL;DR I am really not sure what I am treating as string here ?

EDIT TO ADD....

Even if I greatly simplify my code, I can still reproduce:

<?php
error_reporting (E_ALL | E_STRICT);
ini_set ('display_errors', 1);
$arrX=array(array("c_id"=>"A"),array("c_id"=>"B"));
$collection=new \CachingIterator(new \ArrayIterator($arrX));
foreach($collection as $element) {
echo $element["c_id"].PHP_EOL;
}

Notice: Array to string conversion in /Users/bp/tmp/test.php on line 6

A

Notice: Array to string conversion in /Users/bp/tmp/test.php on line 6

B

The short answer is, you're inadvertently asking the CachingIterator to convert the sub-arrays to strings during iteration. To not do this, don't use the CachingIterator::CALL_TOSTRING or CachingIterator::TOSTRING_USE_INNER flags.

You can set no flags, by using 0 as the value for the $flags parameter, or use a different flag: this can be done in the constructor, or after initialisation by using CachingIterator::setFlags().

For example:

$array = [["c_id" => "A"], ["c_id" => "B"]];
$collection = new CachingIterator(new ArrayIterator($array), 0);
foreach ($collection as $element) {
    // no E_NOTICE messages, yay!
}

And a few words by way of explanation...

By default, the CachingIterator class sets the CachingIterator::CALL_TOSTRING flag as noted in the PHP manual page on CachingIterator.

public __construct ( Iterator $iterator [, int $flags = self::CALL_TOSTRING ] )

When this flag (or the CachingIterator::TOSTRING_USE_INNER flag) is set, and the CachingIterator::next() method is called (i.e. during iteration) the current value (in this case each sub-array) or the inner iterator (in this case, the ArrayIterator), respectively, is converted to a string and saved internally. This string value is what is returned from CachingIterator::__toString() when one of those flags is used.

When using any of the other flags, the above is not done when calling CachingIterator::next().

You need CachingIterator::FULL_CACHE per this PHP docs comment

<?php
$arrX = array(
    array( "c_id" => "A" ),
    array( "c_id" => "B" )
);
$collection = new \CachingIterator( new \ArrayIterator( $arrX ), CachingIterator::FULL_CACHE );
foreach( $collection as $element )
{
    echo $element["c_id"].PHP_EOL;
}