Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In PHP, is it more efficient to use a lambda expression for a callable than a string (or array)?

In PHP, some function take a "callable" as an argument, meaning you can specify a function to be executed at some point down the line. One example is array_map.

PHP allows you to specify a callable in multiple ways, for example:

// as a string:
$lowerCaseStrings = array_map('strtolower', $arrayOfStrings);

// object methods as an array
// (this could be done with DateTime directly, of course):
class DateFactory {
    private $format;

    public function __construct($format) {
        $this->format = $format;
    }

    public function newDate($dateString) {
        return DateTime::createFromFormat($this->format, $dateString); 
    }
}

$factory = new DateFactory('Y-m-d');
$dates = array_map(array($factory, 'newDate'), $arrayOfDateStrings);

// as a lambda expression / closure:
$dates = array_map(
        function ($dateString) {
            return DateTime::createFromFormat('Y-m-d', $dateString);
        },
        $arrayOfDateStrings
    );

Now, I figure that the latter form gets evaluated by the PHP engine once during compilation, while the other might be evaluated during runtime, probably for each call, meaning using a closure would be far more efficient for a large number of calls. Is that assumption correct?

like image 341
Hanno Fietz Avatar asked Mar 24 '15 07:03

Hanno Fietz


1 Answers

I executed a function several different ways and recorded the run times. It looks like using a string reference to a regular function is much more efficient.

Summary

  1. Normal function definition with array_map():                4.001193714
  2. Lambda definition outside loop with array_map():      10.1116962
  3. Normal function definition and call:                               3.208938837
  4. Lambda definition and call within loop:                       10.32323852
  5. Lambda definition outside loop:                                    9.616424465
  6. Normal function definition and call_user_func():         13.72040915
  7. Lambda definition outside loop and call_user_func(): 19.98814855

Normal function definition and call

$start_time = microtime(true);

function run_this() {
    // Empty function
}

for($i = 0; $i < 5000000; $i++) {
    run_this();
}

print "Execution time: " . (microtime(true) - $start_time) . "\n";
  1. 3.1148610115051
  2. 3.0175619125366
  3. 3.5064949989319
  4. 3.3637712001801
  5. 3.0420050621033

Average: 3.208938837

Lambda definition and call within loop

$start_time = microtime(true);

for($i = 0; $i < 5000000; $i++) {
    $run_this = function () {
        // Empty function
    };
    $run_this();
}

print "Execution time: " . (microtime(true) - $start_time) . "\n";
  1. 9.857855797
  2. 10.07680297
  3. 10.35639596
  4. 10.51450491
  5. 10.81063294

Average: 10.32323852

Lambda definition outside loop

$start_time = microtime(true);

$run_this = function () {
    // Empty function
};

for($i = 0; $i < 5000000; $i++) {
    $run_this();
}

print "Execution time: " . (microtime(true) - $start_time) . "\n";
  1. 9.098902941
  2. 9.580584049
  3. 9.370799065
  4. 9.90805316
  5. 10.12378311

Average: 9.616424465

Normal function definition and call_user_func()

$start_time = microtime(true);

function run_this () {
    // Empty function
};

for($i = 0; $i < 5000000; $i++) {
    call_user_func('run_this');
}

print "Execution time: " . (microtime(true) - $start_time) . "\n";
  1. 12.80056691
  2. 13.47905684
  3. 14.51880193
  4. 13.79459596
  5. 14.00902414

Average: 13.72040915

Lambda definition and outside loop and call_user_func()

$start_time = microtime(true);

$run_this = function () {
    // Empty function
};

for($i = 0; $i < 5000000; $i++) {
    call_user_func($run_this);
}

print "Execution time: " . (microtime(true) - $start_time) . "\n";
  1. 18.99004483
  2. 20.08601403
  3. 20.52800584
  4. 20.16949892
  5. 20.16717911

Average: 19.98814855

Normal function definition with array_map()

$arr = array_pad([], 5000, 0);

$start_time = microtime(true);

function run_this () {
    // Empty function
};

for($i = 0; $i < 1000; $i++) {
    array_map('run_this', $arr);
}

print "Execution time: " . (microtime(true) - $start_time) . "\n";
  1. 3.727953911
  2. 4.213405848
  3. 4.068621874
  4. 4.180392027
  5. 3.815594912

Average: 4.001193714

Lambda definition outside loop with array_map()

$arr = array_pad([], 5000, 0);

$start_time = microtime(true);

$run_this = function () {
    // Empty function
};

for($i = 0; $i < 1000; $i++) {
    array_map($run_this, $arr);
}

print "Execution time: " . (microtime(true) - $start_time) . "\n";
  1. 9.418456793
  2. 10.07496095
  3. 10.1241622
  4. 10.74794412
  5. 10.19295692

Average: 10.1116962

like image 86
Wes Dean Avatar answered Nov 19 '22 04:11

Wes Dean