Skip to content

Instantly share code, notes, and snippets.

@browner12
Created May 12, 2017 17:21
Show Gist options
  • Save browner12/9b641b0ca422e8df4d6b8ae916ce917d to your computer and use it in GitHub Desktop.
Save browner12/9b641b0ca422e8df4d6b8ae916ce917d to your computer and use it in GitHub Desktop.
Gate Optimization

I have been doing a lot of work on the Gate class lately. While adding some new features and fixing a bug, I came across something interesting.

When defining Gates, you can set the ability to either a closure or a string using the '@' notation to reference a class method. If you use a closure, it will add it directly to the abilities property. If you use the '@' notation, it will resolve the method and add that resulting closure to the abilities property.

This got me thinking about whether it was more efficient (memory and speed) to resolve the string when defining the abilities and storing the closure on the property, or storing the string on the abilities property and resolving it only when actually called.

A priori, it seems reasonable that the closures are going to be more memory intensive than the strings. Regarding speed, I had no idea if there would be a significant difference either way.

I created the memory.php and speed.php poorman's benchmarks to try testing this. From the results of these scripts, it appears that the 'String' option is much better in terms of memory, and that there is no discernable difference between the two in regards to speed.

I'll be the first to admit I'm out of my element on this benchmarking, so I was hoping for some feedback on this before submitting a PR. If I'm way off base please let me know, or if there are some improvements I could make to measure the memory or speed it would be much appreciated!

<?php
class StringClass
{
private $abilities = [];
public function __construct($count = 1)
{
for ($a = 1; $a <= $count; $a++) {
$this->abilities['key' . $a] = 'value' . $a;
}
}
}
class ArrayClass
{
private $abilities = [];
public function __construct($count = 1)
{
for ($a = 1; $a <= $count; $a++) {
$this->abilities['key' . $a] = ['blue' . $a, 'green' . $a, 'red' . $a];
}
}
}
class ClosureClass
{
private $abilities = [];
public function __construct($count = 1)
{
for ($a = 1; $a <= $count; $a++) {
$this->abilities['key' . $a] = function () use ($a) {
return 'value' . $a;
};
}
}
}
echo '<table border="1"><tr><td>#</td><td>String Memory</td><td>Closure Memory</td><td>Array Memory</td></tr>';
for ($a = 1; $a <= 1000; $a++) {
$mem1 = memory_get_usage();
$class1 = new StringClass($a);
$mem2 = memory_get_usage();
$class2 = new ClosureClass($a);
$mem3 = memory_get_usage();
$class3 = new ArrayClass($a);
$mem4 = memory_get_usage();
unset($class1, $class2, $class3);
echo '<tr><td>';
echo $a;
echo '</td><td>';
echo $mem2 - $mem1;
echo '</td><td>';
echo $mem3 - $mem2;
echo '</td><td>';
echo $mem4 - $mem3;
echo '</td>';
}
echo '</table>';
<?php
class StringGate
{
private $abilities = [];
public function __construct($count = 1)
{
for ($a = 1; $a <= $count; $a++) {
$this->abilities[$a] = 'update';
}
}
public function authorize($ability)
{
$method = $this->abilities[$ability];
$class = new Policy();
return $class->{$method}($ability);
}
}
class ClosureGate
{
private $abilities = [];
public function __construct($count = 1)
{
for ($a = 1; $a <= $count; $a++) {
$this->abilities[$a] = function () use ($a) {
$policy = new Policy();
return $policy->update($a);
};
}
}
public function authorize($ability)
{
return $this->abilities[$ability]($ability);
}
}
class Policy
{
public function update($a)
{
return ($a % 2 == 1) ? 'true' : 'false';
}
}
echo '<table border="1"><tr><td>#</td><td>String Speed</td><td>Result</td><td>Closure Speed</td><td>Result</td><td>Winner</td></tr>';
for ($a = 1; $a <= 1000; $a++) {
$stringGate = new StringGate($a);
$closureGate = new ClosureGate($a);
/*var_dump($stringGate);
var_dump($closureGate);
die;*/
$time1 = microtime(true);
$stringResult = $stringGate->authorize($a);
$time2 = microtime(true);
$closureResult = $closureGate->authorize($a);
$time3 = microtime(true);
$stringTime = $time2 - $time1;
$closureTime = $time3 - $time2;
unset($stringGate, $closureGate);
echo '<tr><td>';
echo $a;
echo '</td><td>';
echo round(($stringTime) * 1000000, 2) . '&micro;s';
echo '</td><td>';
echo $stringResult;
echo '</td><td>';
echo round(($closureTime) * 1000000, 2) . '&micro;s';
echo '</td><td>';
echo $closureResult;
echo '</td><td>';
echo ($stringTime > $closureTime) ? 'Closure' : 'String';
echo '</td>';
}
echo '</table>';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment