Tobiasz Cudnik

Having fun using PHP 5.3 closures with phpQuery

In phpQuery on 08.01.2009 at 16:34

Some time ago i’ve wrote about new PHP 5.3 closures feature. Today i would like to show you it in action with phpQuery. If you’re using jQuery you will feel like in home :)

First example illustrates classic inline function, which is used to iterate over li nodes, incrementing each one’s content.

$markup = '
<ul>
	<li>1</li>
	<li>2</li>
	<li>3</li>
</ul>
';
$doc = phpQuery::newDocument($markup);
$doc['li']->each(function($node){
	pq($node)->text(
		pq($node)->text()+1
	);
});
print $doc;

Result will be someting like this (something because i’ve corrected indentation manually).

<ul>
	<li>2</li>
	<li>3</li>
	<li>4</li>
</ul>

Now more complicated stuff – scope inheritance. Scope inheritance means nothing else than ability to use variables declared outside code block (inline function in this case) inside this particular block. In JavaScript we have full inheritance right away. In PHP 5.3 we have to explicitly declare which variable we would like to inherit. It’s done by use keyword.

$markup = '
<div>
	<span>1</span>
	<span>2</span>
	<span>3</span></div>
<div>
	<span>1</span>
	<span>2</span>
	<span>3</span></div>
';
$doc = phpQuery::newDocument($markup);
$doc['div']->each(function($div){
	$div = pq($div);
	$div['span']->each(function($span) use ($div){
		pq($span)->insertBefore($div);
	});
});
print $doc;

We’ve nested one closure inside another. The inner one inherits $div variable from the outer. Lack of such feature for create_function was really problematic. Below you can see the result. Both divs are now empty.

<span>1</span>
<span>2</span>
<span>3</span>
<div></div>
<span>1</span>
<span>2</span>
<span>3</span>
<div></div>

Third example i want to show is about assigning inline function to a variable. It’s handful technique to avoid namespace collisions and of course allow easily pass closure thou the parts of code.

$markup = '
<div>1</div>
<div>2</div>
<div>3</div>
';
$callback = function($node){
	$node = pq($node);
	$node->text(
		'Callbacked: '.$node->text()
	);
};
print phpQuery::newDocument($markup)
	->find('div')->each($callback)->end();

Just how you suspect, every node’s content will be prefixed with “Callbacked: “.

<div>Callbacked: 1</div>
<div>Callbacked: 2</div>
<div>Callbacked: 3</div>

I think that this post clearly illustrates how closures work and that they are important for PHP as web development language.

If you would like to test code from this post and PHP 5.3 in general, download windows build from php.net or compile source yourself for other platform. CLI version will be enough, that means no apache module struggling.