Quelles sont les différences entre les fermetures dans JS et les fermetures en PHP? Travaillent-ils à peu près de la même manière? Y a-t-il des mises en garde à prendre en compte lors de la rédaction de fermetures en PHP?
Réponses
Trop de publicités?Une différence est comment faire face à stocker le contexte dans lequel une fonction anonyme est exécutée:
// JavaScript:
var a = 1;
var f = function() {
console.log(a);
};
a = 2;
f();
// will echo 2;
// PHP
$a = 1;
$f = function() {
echo $a;
};
$a = 2;
$f();
// will result in a "PHP Notice: Undefined variable: a in Untitled.php on line 5"
Pour corriger cet avis vous devez utiliser l' use
syntaxe:
$a = 1;
$f = function() use ($a) {
echo $a;
};
$a = 2;
$f();
// but this will echo 1 instead of 2 (like JavaScript)
Pour avoir la fonction anonyme, à se comporter d'une certaine manière comme l'équivalent JavaScript, vous aurez à utiliser des références:
$a = 1;
$f = function() use (&$a) {
echo $a;
};
$a = 2;
$f();
// will echo 2
Je pense que c'est la différence la plus frappante entre le JavaScript et le PHP fermetures.
Deuxième différence , c'est que chaque JavaScript fermeture a un this
contexte de la disposition, ce qui signifie que vous pouvez utiliser this
à l'intérieur de la fermeture elle-même (même si c'est souvent assez compliqué de comprendre à quel this
, désigne en fait) - PHP de la version stable actuelle (PHP 5.3) ne supporte pas encore $this
à l'intérieur d'une clôture, mais PHP prochaine version (PHP 5.4) soutiendra $this
de liaison et de travaux de reliure à l'aide de $closure->bind($this)
(Voir l' Objet de l'Extension de la RFC pour plus d'info.)
Troisième différence est de savoir comment les deux langues traiter les fermetures attribué aux propriétés de l'objet:
// JavaScript
var a = {
b: function() {}
};
a.b(); // works
// PHP
$a = new stdClass();
$a->b = function() {};
$a->b(); // does not work "PHP Fatal error: Call to undefined method stdClass::b() in Untitled.php on line 4"
$f = $a->b;
$f(); // works though
Le même est vrai si les fermetures sont affectés à des propriétés dans les définitions de classe:
class A {
public $b;
public function __construct() {
$this->b = function() {};
}
public function c() {
$this->b();
}
}
$a = new A();
// neither
$a->b();
// nor
$a->c();
// do work
Quatrième différence: JavaScript Fermetures sont à part entière des objets, wheres en PHP, ils sont limités objets. Par exemple, PHP Fermetures ne peut pas avoir de propriétés qui leur sont propres:
$fn = function() {};
$fn->foo = 1;
// -> Catchable fatal error: Closure object cannot have properties
alors qu'en JavaScript que vous pouvez faire:
var fn = function() {};
fn.foo = 1;
fn.foo; // 1
Cinquième différence: Retourné, les fermetures peuvent être immédiatement appelé en Javascript:
var fn = function() { return function() { alert('Hi');}}
fn()();
Pas en PHP:
$fn = function() { return function() { echo('Hi');};};
$fn()(); // syntax error
La seule chose que j'ai trouvé en PHP (ce qui est tout à fait cool et vraiment pratique!) c'est la capacité à les utiliser comme des getters et setters dans des classes qui a toujours été un cauchemar pour atteindre avant, JavaScript peut être utilisé de la même manière, mais ils n'agissent presque à l'identique de ce que j'ai vu.
Je ne suis pas sûr au sujet de la namespacing convention de différences entre les deux, mais comme @Rijk a souligné il y a une section sur le site de PHP qui leur est dédié
<?php
class testing {
private $foo = 'Hello ';
public $bar = 'Bar';
#Act like a getter and setter!
public static $readout = function ($val = null) {
if (!empty($val)) {
testing::$readout = $val;
}
return testing::$readout;
}
}
Ils sont également très grand pour...
Boucle sur les éléments avec une manette plutôt qu'un nouveau pour/chaque boucle sur la page
Grande pour fournir d'arguments de fonctions/classes
Ce qui est gênant sur eux...
Vous ne pouvez pas catalogué eux, depuis qu'ils sont juste des fonctions...
Ils font à peu près de la même façon. Voici plus d'informations sur l'implémentation PHP: http://php.net/manual/en/functions.anonymous.php
Vous pouvez utiliser un dispositif de fermeture (en PHP appelée "fonction anonyme") comme un rappel:
// return array of ids
return array_map( function( $a ) { return $a['item_id']; }, $items_arr );
et l'assigner à une variable:
$greet = function( $string ) { echo 'Hello ' . $string; }; // note the ; !
echo $greet('Rijk'); // "Hello Rijk"
En outre, la fonction anonyme, 'inherit' le champ dans lequel elles ont été définies comme la JS mise en œuvre, avec un gotcha: vous avez la liste de toutes les variables que vous souhaitez hériter en use()
:
function normalFunction( $parameter ) {
$anonymous = function() use( $parameter ) { /* ... */ };
}
et comme une référence, si vous souhaitez modifier l'orignal variable.
function normalFunction( $parameter ) {
$anonymous = function() use( &$parameter ) { $parameter ++ };
$anonymous();
$parameter; // will be + 1
}