scotteh/php-dom-wrapper

Odd find() behavior

MagicLegend opened this issue · 2 comments

Hi,
First off, I'm just getting started with PHP. Please forgive any sloppy code, I'm just poking around :-) I am familiar with jQuery tho, and this makes that the find() function has some odd behavior in my mind.

I would expect an element when I do a find(). But instead I get the contents of all the elements that match. For my case I specifically need the elements (I need to process their attributes). I have tried some things on the given example code (to eliminate any issue with the gigantic html that I'm providing it)

$html = '<ul>
    <li class="test"><div my-attribute="value">First</div></li>
    <li>Second</li>
    <li class="test">Third</li>
</ul>';

$doc = new Document();
$doc->html($html);
$nodes = $doc->find('.test');
$output = $nodes->attr('my-attribute');

var_dump($nodes);
var_dump($output);
// Returns '3'
var_dump($nodes->count());

Chaining the commands ($nodes = $doc->find('.test')->attr('my-attribute');) gives the same problem. When do the (...)->find('.test'); I would expect it returning <div my-attribute="value">First</div> and Third. Instead it now returns First and Third. This would mean that any further manipulation is impossible after a find().

Is this intended behavior? Is there a workaround available to get the content of any element matching a specific class?

It's quite similar to jQuery in behavior, but keep in mind using var_dump() much like console.log() for jQuery objects will output a lot of internal state.

The php-dom-wrapper library 'wraps' the PHP DOM classes via DOMDocument:registerNodeClasses(). As such using var_dump() on them doesn't give you much.

Similar to jQuery all find/selector based functions return an 'array' of results. Some functions you can chain onto these will either work on the first result (eg: ->attr() as a getter), all of them (eg: ->remove() or ->attr() as a setter) or potentially some other variation (eg: ->last()).

Your example looked to have an issue or two so I've adjusted and provided examples using both php-dom-wrapper and jQuery that should be fairly equivalent. Both use the initial HTML as the source.

HTML

<ul>
    <li class="test"><div my-attribute="value">First</div></li>
    <li>Second</li>
    <li class="test">Third</li>
</ul>

php-dom-wrapper

$doc = new Document();
$doc->html($html);
$nodes = $doc->find('.test');
$attr = $nodes->find('div')->attr('my-attribute');

var_dump($nodes); // NodeList object
var_dump($attr); // value
var_dump($nodes->count()); // 2

jQuery

var $nodes = $('.test'),
    $attr = $nodes.find('div').attr('my-attribute');

console.log($nodes); // jQuery object
console.log($attr); // value
console.log($nodes.length) // 2

Similar to jQuery if you are after a specific element returned from ->find() consider using ->eq(), ->first(), ->last() or for looping over results you could use ->each().

Hopefully this helps.

Thank you for the extensive answer. I should have clarified in my first post that I was looking at the debug view Intellij provides, in combination with xdebug. This gives me a field, nodeValue, which I assumed was the 'output' of the ->find(). This assumption was further fueled by the textContent field, which does what I expected, but shows the same content as nodeValue.

This is porting some jQuery code I wrote to PHP, and looking at your example it looks like I was a bit confused by the shortcut I took there. There my selector just looks like "div[attribute='value']". This indeed includes the find('div') that I missed when rewriting this into php-dom-wrapper. Thank you for pointing that out, and the working examples with a jQuery version. Perhaps they are nice to add to the readme file, to provide a simple example of how commands are able to be chained.

Again, thank you for the amazing plugin and the answer!