k0pernikus
k0pernikus

Reputation: 66717

How to properly typehint SimpleXMLElement?

Is there a way to properly typehint a \SimpleXMLElement? So that I do not have to typehint all what it accesses also a a \SimpleXMLElement?

If I want to have typehinting all the way, I currently have to do it this way:

   /**
     * @var \SimpleXMLElement $values (this is not! an array, yet it is traversable)
     */
    $values = $response->params->param->value->array->data->value;
    foreach ($values as $row) {
        $row = $row->array->data->value;

        /**
         * @var \SimpleXMLElement $row
         */

        $entry = $row[0];

        /**
         * @var \SimpleXMLElement $entry
         */
        $xmlString = $entry->asXML();
}

This seems utterly verbose and redundant. Is there a way to typehint a SimpleXMLElement so that all what it returns will also be coreclty typehinted?

Upvotes: 1

Views: 553

Answers (1)

IMSoP
IMSoP

Reputation: 97898

If you Ctrl-click through to the "definition" of SimpleXMLElement in PHPStorm, you will see that it has a stub class definition which it uses for auto-completion and code analysis.

In older versions of PHPStorm, the overloaded -> operator was represented in that stub as follows (taken from PHPStorm 9.0):

/**
 * Provides access to element's children
 * @param $name child name
 * @return SimpleXMLElement[]
 */
function __get($name) {}

Note that the return type here is SimpleXMLElement[], i.e. "an array of SimpleXMLElement objects". This allows it to correctly auto-complete if you write something like $node->childName[0]->grandChild[0]->asXML(), but not if you use the short-hand form of $node->childName->grandChild->asXML()

This could be classed as a bug in the IDE, and was filed in their public tracker as WI-15760, which is now fixed.

As of PHPStorm 2018.1.2, the stub instead declares the return type of __get() as SimpleXMLElement and also declares implements ArrayAccess with offsetGet() also returning SimpleXMLElement.

/**
 * Provides access to element's children
 * @access private Method not callable directly, stub exists for typehint only
 * @param string $name child name
 * @return SimpleXMLElement
 */
private function __get($name) {}

/**
 * Class provides access to children by position, and attributes by name
 * @access private Method not callable directly, stub exists for typehint only
 * @param string|int $offset
 * @return SimpleXMLElement Either a named attribute or an element from a list of children
 */
private function offsetGet ($offset) {}

This should correctly auto-complete for both explicit [0] and short-hand cases.

(The @access private is a hack to stop the method showing up in auto-complete results, since you can't actually call $node->__get() or $node->offsetGet() in real PHP code.)

Upvotes: 4

Related Questions