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!