En PHP, les paramètres de fonction peuvent être passés par référence en ajoutant une esperluette au paramètre dans la déclaration de fonction, comme ceci:
function foo(&$bar)
{
// ...
}
Maintenant, je suis conscient que c'est ne pas conçu pour améliorer les performances, mais pour permettre aux fonctions de modifier des variables qui sont normalement hors de leur portée.
Au lieu de cela, PHP semble utiliser Copy On Write pour éviter de copier des objets (et peut-être aussi des tableaux) jusqu'à ce qu'ils soient modifiés. Ainsi, pour les fonctions qui ne modifient pas leurs paramètres, l'effet devrait être le même comme si vous les aviez transmis par référence.
Cependant, je me demandais si la logique de copie en écriture est peut-être court-circuitée par référence et si cela a un impact sur les performances.
ETA: Pour être sûr, je suppose que ce n'est pas plus rapide, et je suis bien conscient que ce ne sont pas les références. Je pense donc que mes propres suppositions sont assez bonnes, je cherche juste une réponse de quelqu'un qui sait vraiment ce qui se passe définitivement sous le capot. En cinq ans de développement PHP, j'ai toujours eu du mal à obtenir des informations de qualité sur PHP internes à court de lecture de la source).
Le moteur Zend utilise la copie sur écriture, et lorsque vous utilisez vous-même une référence, cela entraîne un peu de surcharge supplémentaire. Je ne trouve que cette mention au moment de la rédaction, et les commentaires dans le manuel contiennent d'autres liens.
(EDIT) La page de manuel sur Objets et références contient un peu plus d'informations sur la façon dont les variables d'objet diffèrent des références.
Dans un test avec 100 000 itérations d'appel d'une fonction avec une chaîne de 20 ko, les résultats sont:
pass by value: 0.12065005 seconds
pass by reference: 1.52171397 seconds
pass by value: 1.52223396 seconds
pass by reference: 1.52388787 seconds
Passer le paramètre par valeur est toujours plus rapide
Si la fonction change la valeur de la variable passée, pour des raisons pratiques, c'est la même chose que passer par référence que par valeur
J'ai effectué un test à ce sujet parce que je n'étais pas sûr des réponses données.
Mes résultats montrent que le passage de grands tableaux ou chaînes par référence IS beaucoup plus rapide.
Voici mes résultats:
L'axe Y (Runs) est le nombre de fois qu'une fonction peut être appelée en 1 seconde * 10
Le test a été répété 8 fois pour chaque fonction/variable
Et voici les variables que j'ai utilisées:
$large_array = array_fill(PHP_INT_MAX / 2, 1000, 'a');
$small_array = array('this', 'is', 'a', 'small', 'array');
$large_object = (object)$large_array;
$large_string = str_repeat('a', 100000);
$small_string = 'this is a small string';
$value = PHP_INT_MAX / 2;
Ce sont les fonctions:
function pass_by_ref(&$var) {
}
function pass_by_val($var) {
}
J'ai expérimenté avec des valeurs et des références de chaîne de 10k octets en le passant à deux fonctions identiques. L'un prend l'argument par valeur et le second par référence. C'étaient des fonctions courantes - prendre un argument, effectuer un traitement simple et renvoyer une valeur. J'ai fait 100 000 appels des deux et j'ai compris que les références ne sont pas conçues pour augmenter les performances - le bénéfice de référence était proche de 4-5% et il ne croît que lorsque la chaîne devient suffisamment grande (100k et plus, ce qui a donné une amélioration de 6-7%) . Donc, ma conclusion est n'utilisez pas de références pour augmenter les performances, ce n'est pas pour ça.
J'ai utilisé PHP Version 5.3.1
Je suis sûr que non, ce n'est pas plus rapide. De plus, il indique spécifiquement dans le manuel de ne pas essayer d'utiliser des références pour augmenter les performances.
Edit: Impossible de trouver où il est dit cela, mais il est là!
Il n'y a rien de mieux qu'un morceau de code de test
<?PHP
$r = array();
for($i=0; $i<500;$i++){
$r[]=5;
}
function a($r){
$r[0]=1;
}
function b(&$r){
$r[0]=1;
}
$start = microtime(true);
for($i=0;$i<9999;$i++){
//a($r);
b($r);
}
$end = microtime(true);
echo $end-$start;
?>
Résultat final! Plus le tableau est grand (ou plus le nombre d'appels est important), plus la différence est grande. Dans ce cas, l'appel par référence est donc plus rapide car la valeur est modifiée à l'intérieur de la fonction.
Sinon, il n'y a pas de réelle différence entre "par référence" et "par valeur", le compilateur est suffisamment intelligent pour ne pas créer une nouvelle copie à chaque fois s'il n'y a pas besoin.
Est simple, il n'est pas nécessaire de tester quoi que ce soit. Dépend du cas d'utilisation.
Le passage par valeur sera TOUJOURS PLUS RAPIDE EN VALEUR que la référence pour une petite quantité d'arguments. Cela dépend du nombre de variables que l'architecture permet de passer par les registres (ABI).
Par exemple, x64 vous permettra de passer 4 valeurs de 64 bits chacune dans les registres. https://en.wikipedia.org/wiki/X86_calling_conventions
C'est parce que vous n'avez pas à dé-référencier les pointeurs, utilisez simplement la valeur directement.
Si vos données à transmettre sont plus grandes que ABI, le reste des valeurs ira dans la pile. Dans ce cas, un tableau ou un objet (qui est par exemple une classe ou une structure + en-têtes) SERA TOUJOURS PLUS RAPIDE PAR RÉFÉRENCE.
En effet, une référence n'est qu'un pointeur vers vos données (pas les données elles-mêmes), de taille fixe, disons 32 ou 64 bits selon la machine. Ce pointeur tiendra dans un registre CPU.
PHP est écrit en C/C++ donc je m'attends à ce qu'il en soit de même.
J'ai essayé de comparer cela avec un exemple du monde réel basé sur un projet sur lequel je travaillais. Comme toujours, les différences sont minimes, mais les résultats étaient quelque peu inattendus. Pour la plupart des benchmarks que j'ai vus, la fonction appelée ne change pas réellement la valeur transmise. J'ai effectué un simple str_replace () dessus.
**Pass by Value Test Code:**
$originalString=''; // 1000 pseudo-random digits
function replace($string) {
return str_replace('1', 'x',$string);
}
$output = '';
/* set start time */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tstart = $mtime;
set_time_limit(0);
for ($i = 0; $i < 10; $i++ ) {
for ($j = 0; $j < 1000000; $j++) {
$string = $originalString;
$string = replace($string);
}
}
/* report how long it took */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tend = $mtime;
$totalTime = ($tend - $tstart);
$totalTime = sprintf("%2.4f s", $totalTime);
$output .= "\n" . 'Total Time' .
': ' . $totalTime;
$output .= "\n" . $string;
echo $output;
Passer par le code de test de référence
La même chose sauf pour
function replace(&$string) {
$string = str_replace('1', 'x',$string);
}
/* ... */
replace($string);
Résultats en secondes (10 millions d'itérations):
PHP 5
Value: 14.1007
Reference: 11.5564
PHP 7
Value: 3.0799
Reference: 2.9489
La différence est une fraction de milliseconde par appel de fonction, mais pour ce cas d'utilisation, le passage par référence est plus rapide dans les deux PHP 5 et PHP 7.
(Remarque: les tests PHP 7 ont été effectués sur une machine plus rapide - PHP 7 est plus rapide, mais probablement pas beaucoup plus rapide.)