Leo Jiang
Leo Jiang

Reputation: 26253

Global variable or pass variable in PHP? (performance)

If I have the option of using a global variable or passing a variable, which option is better in terms of speed and memory usage?

// global variable
function func(){
  global $var;
  echo $var;
}

$var='string';
func();


// passing variable
function func($var){
  echo $var;
}

$var='string';
func($var);

Upvotes: 2

Views: 2996

Answers (5)

magallanes
magallanes

Reputation: 6854

Tl/dr: define const=const > parameter > global > $GLOBAL

However, the difference is really marginal, for 10 millions of operations, the difference is less than a second.

I ran the example of @Kevin Vaughan (I ran it 10'000'000 instead of 1'000'000) Windows 10 64bits, php 7.2 64bits

    Pass value by parameter
Time: 0.62202191352844s
Memory: 0

Global var reference
Time: 0.70083403587341s
Memory: 0

GLOBALS array reference
Time: 0.84828305244446s
Memory: 0

GLOBALS array reference2
Time: 0.80545091629028s
Memory: 0

GLOBALS array const define
Time: 0.57029700279236s
Memory: 0

GLOBALS array const
Time: 0.57260584831238s
Memory: 0

The memory leak is gone, however, the difference of performance is really small. Yet, passing the values by parameter is still fast.

Updated code with new functions.

<?php
echo "<pre>";
$baseVar = str_repeat('x', 1000000);
$GLOBALS['myVar'] = $baseVar;
define('BASEVAR',$baseVar);

const BASEVAR2=BASEVAR;

function testfunc_param($paramVar) {
    $localVar = $paramVar;
    return $localVar;
}

function testfunc_global() {
    global $myVar;
    $localVar = $myVar;
    return $localVar;
}

function testfunc_globalsarray() {
    $localVar = $GLOBALS['myVar'];
    return $localVar;
}

function testfunc_globalsarray2() {
    return $GLOBALS['myVar'];
}

function testfunc_const() {
    return BASEVAR;
}

function testfunc_const2() {
    return BASEVAR2;
}

// Testing passing value by parameter
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    testfunc_param($baseVar);
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "Pass value by parameter\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";


// Testing reference to global variable
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    testfunc_global();
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "Global var reference\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";


// Testing reference to global variable via $GLOBALS
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    testfunc_globalsarray();
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "GLOBALS array reference\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";

// Testing reference to global variable via $GLOBALS
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    testfunc_globalsarray2();
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "GLOBALS array reference2\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";

// Testing reference to global variable via $GLOBALS
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    testfunc_const();
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "GLOBALS array const define\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";

// Testing reference to global variable via $GLOBALS
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    testfunc_const2();
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "GLOBALS array const\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";


echo "</pre>";

Upvotes: 3

Kevin Vaughan
Kevin Vaughan

Reputation: 15220

TLDR: Pass by parameter = $GLOBALS element >>> global $var

When in doubt, test! The below results show that:

  1. Passing a 1Mb string by parameter is vastly more performant than ref by global $var
  2. Passing a 1Mb string by parameter is approximately equally performant as using $GLOBALS['var']
  3. Using global $var in the below manner seems to mess with GC reference counts on the memory and is ridiculously slow. Apparently, don't use global $var for cases like this made up one.

Results (see code further below):
Time is seconds elapsed, memory is memory potentially leaked.

$ php -e test.php
Pass value by parameter
Time: 0.20166087150574s
Memory: 0

Global var reference
Time: 70.613216876984s
Memory: 1048576

GLOBALS array reference
Time: 0.22573900222778s
Memory: 0

Test Code:

<?php

$baseVar = str_repeat('x', 1000000);
$GLOBALS['myVar'] = $baseVar;

function testfunc_param($paramVar) {
    $localVar = $paramVar;
    return $localVar;
}

function testfunc_global() {
    global $myVar;
    $localVar = $myVar;
    return $localVar;
}

function testfunc_globalsarray() {
    $localVar = $GLOBALS['myVar'];
    return $localVar;
}


// Testing passing value by parameter
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    testfunc_param($baseVar);
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "Pass value by parameter\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";


// Testing reference to global variable
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    testfunc_global();
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "Global var reference\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";


// Testing reference to global variable via $GLOBALS
memory_get_usage(); // in case this procs garbage collection
$memoryStart = memory_get_usage(true);
$timeStart = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    testfunc_globalsarray();
}
$timeEnd = microtime(true);
$memoryEnd = memory_get_usage(true);
print "GLOBALS array reference\nTime: ".($timeEnd - $timeStart)."s\nMemory: ".($memoryEnd-$memoryStart)."\n\n";

Upvotes: 6

Korvin Szanto
Korvin Szanto

Reputation: 4511

In PHP, global $var is essentially running $var = &$_GLOBALS['var'] behind the scenes, so you'd be looking at a search time of O(n). The cost in running the function with the variable passed in is so little that it's not worth optimizing against.

Generally, you should find a balance between what is functionally correct, what is easy to read / test, and what is fast. In this case, the speed difference is negligible, while the cost to overall readability and testability is pretty severe.

Upvotes: 2

Gonz
Gonz

Reputation: 1219

I don't think you would see any performance difference. But you should be aware it's not a good idea to use a global variable just for doing it. Eventually it would be a problem, for reading the code, developing and testing.

Upvotes: 1

Guntram Blohm
Guntram Blohm

Reputation: 9819

The global variable will probably be faster, but not in a way that it's detectable unless you microbenchmark it. So base your decisions on which code is more readable/maintainable (which will be passing the variable in almost all cases), not some speed advantage you'll normally never notice.

Upvotes: 3

Related Questions