Sean D
Sean D

Reputation: 4292

PHP: Looping over an object loops over member array

foreach ($pElements as $pElement) {
  var_dump($pElement);
}

If I execute the above, I notice it dumps each value in the 'nodes' array even though $pElement is an object. Can anyone explain this behavior?

At first I thought running foreach on an object automatically searches for a member array, but the first listed array namespaces seems to be ignored.

Here is the full object $pElements:

/var/www/html/phpTestArea/index.php:35:
object(Symfony\Component\DomCrawler\Crawler)[38]
  protected 'uri' => null
  private 'defaultNamespacePrefix' => string 'default' (length=7)
  private 'namespaces' => 
    array (size=0)
      empty
  private 'baseHref' => null
  private 'document' => 
    object(DOMDocument)[2]
      public 'doctype' => string '(object value omitted)' (length=22)
      public 'implementation' => string '(object value omitted)' (length=22)
      <public properties removed>
  private 'nodes' => 
    array (size=2)
      0 => 
        object(DOMElement)[36]
        <public properties removed>              
      1 => 
        object(DOMElement)[35]
        <public properties removed>
  private 'isHtml' => boolean true

Upvotes: 0

Views: 55

Answers (1)

mdexp
mdexp

Reputation: 3567

If you take a look at the source code of that class here, you can see that it implements two interfaces, defined as follow:

Countable: this define how the instances of the class should behave when passed to the native php count function. The counting depends on the implementation.

interface Countable {
    abstract public count(void): int
}

IteratorAggregate: this is the one that return an iterator (which extends Traversable) that defines how and what should be traversed.

interface IteratorAggregate extends Traversable {
    abstract public getIterator(void): Traversable
}

So if you look closely into the source code for these two functions, you will see how these are implemented:

/**
 * @return int
 */
public function count()
{
    return \count($this->nodes);
}

/**
 * @return \ArrayIterator|\DOMElement[]
 */
public function getIterator()
{
    return new \ArrayIterator($this->nodes);
}

So if you call count($pElements), the object's internal count function will be executed, therefore you would get the count of the nodes property.

In the same way, if you iterate with a foreach over $pElements, you are iterating over the nodes property, as this is the behaviour defined by getIterator().

Upvotes: 1

Related Questions