Domanda

In PHP, i parametri della funzione possono essere passati per riferimento anteponendo una e commerciale al parametro nella dichiarazione della funzione, in questo modo:

function foo(&$bar)
{
    // ...
}

Ora, sono consapevole che questo non è non progettato per migliorare le prestazioni, ma per consentire alle funzioni di cambiare le variabili che normalmente sono al di fuori del loro ambito.

Invece, PHP sembra usare Copia su scrittura per evitare di copiare oggetti (e forse anche matrici) fino a quando non vengono modificati. Quindi, per le funzioni che non cambiano i loro parametri, l'effetto dovrebbe essere lo stesso di se li avessi passati per riferimento.

Tuttavia, mi chiedevo se la logica Copia su scrittura fosse forse in cortocircuito sul pass-by-reference e se ciò avesse un impatto sulle prestazioni.

ETA: A dire il vero, presumo che non sia più veloce e sono ben consapevole del fatto che questo non è il riferimento. Quindi penso che le mie ipotesi siano abbastanza buone, sto solo cercando una risposta da qualcuno che sa davvero cosa sta succedendo sotto il cofano. In cinque anni di sviluppo di PHP, ho sempre trovato difficile ottenere informazioni di qualità sugli interni di PHP a corto di lettura della fonte.

È stato utile?

Soluzione

Zend Engine utilizza la funzione di copia su scrittura e, quando si utilizza un riferimento da soli, comporta un ulteriore sovraccarico. È possibile trovare questa menzione al momento in cui scrivo, e i commenti in il manuale contengono altri collegamenti.

(EDIT) La pagina del manuale su Oggetti e riferimenti contiene qualche informazione in più su come le variabili oggetto differiscono dai riferimenti.

Altri suggerimenti

In un test con 100.000 iterazioni di chiamata di una funzione con una stringa di 20 kB, i risultati sono:

Funzione che legge / utilizza il parametro

pass by value:      0.12065005 seconds
pass by reference:  1.52171397 seconds

Funzione per scrivere / modificare il parametro

pass by value:      1.52223396 seconds
pass by reference:  1.52388787 seconds

Conclusioni

  1. Passare il parametro in base al valore è sempre più veloce

  2. Se la funzione modifica il valore della variabile passata, ai fini pratici è la stessa del passaggio per riferimento che per valore

Ho eseguito alcuni test su questo perché non ero sicuro delle risposte fornite.

I miei risultati mostrano che il passaggio di matrici o stringhe di grandi dimensioni per riferimento è significativamente più veloce.

Ecco i miei risultati: Benchmark

L'asse Y (corse) indica quante volte una funzione può essere chiamata in 1 secondo * 10

Il test è stato ripetuto 8 volte per ciascuna funzione / variabile

Ed ecco le variabili che ho usato:

$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;

Queste sono le funzioni:

function pass_by_ref(&$var) {
}

function pass_by_val($var) {
}

Ho sperimentato valori e riferimenti della stringa di 10k byte passando a due funzioni identiche. Uno prende argomento per valore e il secondo per riferimento. Erano funzioni comuni: prendi argomento, esegui semplici elaborazioni e restituisci un valore. Ho fatto 100.000 chiamate di entrambi e ho capito che i riferimenti non sono progettati per aumentare le prestazioni - l'utile di riferimento era vicino al 4-5% e cresce solo quando la stringa diventa abbastanza grande (100k e più, che ha dato un miglioramento del 6-7%) . Quindi, la mia conclusione è non usare riferimenti per aumentare le prestazioni, questa roba non è per quello.

Ho usato PHP versione 5.3.1

Sono abbastanza sicuro che no, non è più veloce. Inoltre, nel manuale si dice specificamente di non provare a usare i riferimenti per aumentare le prestazioni.

Modifica: non riesco a trovare dove lo dice, ma è lì!

Non c'è niente di meglio di un pezzo di codice di prova

<?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;
?>

Risultato finale! Maggiore è l'array (o maggiore è il conteggio delle chiamate) maggiore è la differenza. Quindi, in questo caso, chiamare per riferimento è più veloce perché il valore viene modificato all'interno della funzione.

Altrimenti non vi è alcuna differenza reale tra " per riferimento " e "in base al valore", il compilatore è abbastanza intelligente da non creare una nuova copia ogni volta che non è necessario.

Ho provato a confrontarlo con un esempio reale basato su un progetto a cui stavo lavorando. Come sempre, le differenze sono banali, ma i risultati sono stati in qualche modo inaspettati. Per la maggior parte dei benchmark che ho visto, la funzione chiamata non cambia effettivamente il valore passato. Ho eseguito un semplice str_replace () su di esso.

**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;

Passa per codice test di riferimento

Lo stesso tranne

function replace(&$string) {
    $string = str_replace('1', 'x',$string);
}
/* ... */
replace($string);

Risultati in secondi (10 milioni di iterazioni):

PHP 5
    Value:     14.1007
    Reference: 11.5564

PHP 7
    Value:     3.0799
    Reference: 2.9489

La differenza è una frazione di millisecondo per chiamata di funzione, ma per questo caso d'uso, passare per riferimento è più veloce sia in PHP 5 che in PHP 7.

(Nota: i test di PHP 7 sono stati eseguiti su una macchina più veloce - PHP 7 è più veloce, ma probabilmente non molto più veloce.)

È semplice, non è necessario testare nulla. Dipende dal caso d'uso.

Il passaggio per valore sarà SEMPRE PIÙ VELOCE PER VALORE rispetto al riferimento per una piccola quantità di argomenti. Ciò dipende dal numero di variabili che l'architettura consente di passare attraverso i registri (ABI).

Ad esempio, x64 ti permetterà di far passare 4 valori a 64 bit ciascuno attraverso i registri. https://en.wikipedia.org/wiki/X86_calling_conventions

Questo perché non devi de-referenziare i puntatori, usa semplicemente il valore direttamente.

Se i tuoi dati che devono essere passati sono più grandi di ABI, il resto dei valori andrà in pila. In questo caso, un array o un oggetto (che ad esempio è una classe o una struttura + intestazioni) SARANNO SEMPRE PIÙ RAPIDI PER RIFERIMENTO.

Questo perché un riferimento è solo un puntatore ai tuoi dati (non dati stessi), dimensioni fisse, diciamo 32 o 64 bit a seconda della macchina. Tale puntatore si inserirà in un registro CPU.

PHP è scritto in C / C ++ quindi mi aspetto di comportarmi allo stesso modo.

Non è necessario aggiungere & amp; operatore quando passa oggetti. In PHP 5+ gli oggetti vengono comunque passati per riferimento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top