Created
January 3, 2015 23:18
-
-
Save DWand/54ae49470ee8557432a3 to your computer and use it in GitHub Desktop.
Benchmark for a method calling based on variable value in PHP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
ini_set('precision', 16); | |
// How many times to execute a test to get average execution time | |
define('TEST_CALLS', 25); | |
// How many times to execute a loop of validation | |
define('VALIDATION_LOOPS', 1000); | |
// Test classes | |
abstract class Test | |
{ | |
/** | |
* Executes a test | |
* @return float A time taken by the test execution | |
*/ | |
final public function execute() | |
{ | |
$timeStart = 0; | |
$timeStop = 0; | |
$this->init(); | |
$timeStart = microtime(true); | |
$this->test(); | |
$timeStop = microtime(true); | |
return $timeStop - $timeStart; | |
} | |
protected function init() {} | |
public abstract function getName(); | |
protected abstract function test(); | |
} | |
class Tester | |
{ | |
protected $amount; | |
/** | |
* @param int $amount An amount of times to execute a test | |
*/ | |
public function __construct($amount) | |
{ | |
$this->amount = $amount; | |
} | |
/** | |
* Performs testing with a given test | |
* @param Test $test A test to execute | |
*/ | |
public function test(Test $test) | |
{ | |
$time = 0; | |
for ($i = 0; $i < $this->amount; $i++) { | |
$time += $test->execute(); | |
} | |
$time /= (float)$this->amount; | |
echo 'Test "' . $test->getName() . '" has been executed ' . $this->amount . ' times.' . PHP_EOL; | |
echo 'Average execution time is ' . $time . ' sec.' . PHP_EOL; | |
} | |
} | |
//// Test data | |
class HttpRequest | |
{ | |
public function isGetParamPresent() {} | |
public function isPostParamPresent() {} | |
public function isPutParamPresent() {} | |
public function isDeleteParamPresent() {} | |
} | |
// Basic test data | |
abstract class MethodCallTest extends Test | |
{ | |
protected $loops; | |
protected $request; | |
protected $params; | |
public function __construct() | |
{ | |
$this->loops = VALIDATION_LOOPS; | |
$this->request = new HttpRequest(); | |
$this->params = array( | |
array('get', 'param1', 0), | |
array('put', 'param2', 1), | |
array('put', 'param3', 2), | |
array('put', 'param4', 4), | |
array('put', 'param5', 8), | |
array('put', 'param6', 16), | |
array('put', 'param7', 32), | |
); | |
} | |
} | |
//// If / Else sequence approach | |
class IfElseTest extends MethodCallTest | |
{ | |
public function getName() | |
{ | |
return 'If/Else sequense'; | |
} | |
protected function test() | |
{ | |
for ($i = 0; $i < $this->loops; $i++) { | |
foreach ($this->params as $param) { | |
$method = $param[0]; | |
$name = $param[1]; | |
$exists = false; | |
if ($method === 'get') { | |
$exists = $this->request->isGetParamPresent($name); | |
} elseif ($method === 'post') { | |
$exists = $this->request->isPostParamPresent($name); | |
} elseif ($method === 'put') { | |
$exists = $this->request->isPutParamPresent($name); | |
} elseif ($method === 'delete') { | |
$exists = $this->request->isDeleteParamPresent($name); | |
} | |
} | |
} | |
} | |
} | |
//// Switch approach | |
class SwitchTest extends MethodCallTest | |
{ | |
public function getName() | |
{ | |
return 'Switch'; | |
} | |
protected function test() | |
{ | |
for ($i = 0; $i < $this->loops; $i++) { | |
foreach ($this->params as $param) { | |
$method = $param[0]; | |
$name = $param[1]; | |
$exists = false; | |
switch ($method) { | |
case 'get': | |
$exists = $this->request->isGetParamPresent($name); | |
break; | |
case 'post': | |
$exists = $this->request->isPostParamPresent($name); | |
break; | |
case 'put': | |
$exists = $this->request->isPutParamPresent($name); | |
break; | |
case 'delete': | |
$exists = $this->request->isDeleteParamPresent($name); | |
break; | |
} | |
} | |
} | |
} | |
} | |
//// Variable functions approach | |
class VariableFunctionsTest extends MethodCallTest | |
{ | |
protected $functions; | |
public function __construct() | |
{ | |
parent::__construct(); | |
$this->functions = array( | |
'get' => 'isGetParamPresent', | |
'post' => 'isPostParamPresent', | |
'put' => 'isPutParamPresent', | |
'delete' => 'isDeleteParamPresent', | |
); | |
} | |
public function getName() | |
{ | |
return 'Variable functions'; | |
} | |
protected function test() | |
{ | |
for ($i = 0; $i < $this->loops; $i++) { | |
foreach ($this->params as $param) { | |
$method = $this->functions[$param[0]]; | |
$name = $param[1]; | |
$exists = $this->request->$method($name); | |
} | |
} | |
} | |
} | |
//// Anonymous functions approach | |
class AnonymousFunctionsTest extends MethodCallTest | |
{ | |
protected $functions; | |
public function __construct() | |
{ | |
parent::__construct(); | |
$req = $this->request; | |
$this->functions = array( | |
'get' => function($name) use ($req) { return $req->isGetParamPresent($name); }, | |
'post' => function($name) use ($req) { return $req->isPostParamPresent($name); }, | |
'put' => function($name) use ($req) { return $req->isPutParamPresent($name); }, | |
'delete' => function($name) use ($req) { return $req->isDeleteParamPresent($name); }, | |
); | |
} | |
public function getName() | |
{ | |
return 'Anonymous functions'; | |
} | |
protected function test() | |
{ | |
for ($i = 0; $i < $this->loops; $i++) { | |
foreach ($this->params as $param) { | |
$method = $param[0]; | |
$name = $param[1]; | |
$exists = $this->functions[$method]($name); | |
} | |
} | |
} | |
} | |
//// call_user_func usage approach | |
class CallUserFuncTest extends MethodCallTest | |
{ | |
protected $functions; | |
public function __construct() | |
{ | |
parent::__construct(); | |
$this->functions = array( | |
'get' => 'isGetParamPresent', | |
'post' => 'isPostParamPresent', | |
'put' => 'isPutParamPresent', | |
'delete' => 'isDeleteParamPresent', | |
); | |
} | |
public function getName() | |
{ | |
return 'Function call_user_func'; | |
} | |
protected function test() | |
{ | |
for ($i = 0; $i < $this->loops; $i++) { | |
foreach ($this->params as $param) { | |
$method = $this->functions[$param[0]]; | |
$name = $param[1]; | |
$exists = call_user_func(array($this->request, $method), $name); | |
} | |
} | |
} | |
} | |
//// eval usage approach | |
class EvalTest extends MethodCallTest | |
{ | |
protected $functions; | |
public function __construct() | |
{ | |
parent::__construct(); | |
$this->functions = array( | |
'get' => 'return $this->request->isGetParamPresent($name);', | |
'post' => 'return $this->request->isPostParamPresent($name);', | |
'put' => 'return $this->request->isPutParamPresent($name);', | |
'delete' => 'return $this->request->isDeleteParamPresent($name);', | |
); | |
} | |
public function getName() | |
{ | |
return 'Function eval'; | |
} | |
protected function test() | |
{ | |
for ($i = 0; $i < $this->loops; $i++) { | |
foreach ($this->params as $param) { | |
$method = $param[0]; | |
$name = $param[1]; | |
$exists = eval($this->functions[$method]); | |
} | |
} | |
} | |
} | |
//// Reflection approach | |
class ReflectionTest extends MethodCallTest | |
{ | |
protected $functions; | |
public function __construct() | |
{ | |
parent::__construct(); | |
$this->functions = array( | |
'get' => new ReflectionMethod('HttpRequest', 'isGetParamPresent'), | |
'post' => new ReflectionMethod('HttpRequest', 'isPostParamPresent'), | |
'put' => new ReflectionMethod('HttpRequest', 'isPutParamPresent'), | |
'delete' => new ReflectionMethod('HttpRequest', 'isDeleteParamPresent'), | |
); | |
} | |
public function getName() | |
{ | |
return 'Reflection'; | |
} | |
protected function test() | |
{ | |
for ($i = 0; $i < $this->loops; $i++) { | |
foreach ($this->params as $param) { | |
$method = $param[0]; | |
$name = $param[1]; | |
$exists = $this->functions[$method]->invoke($this->request, $name); | |
} | |
} | |
} | |
} | |
//// Polymorphism approach | |
interface ParamValidator | |
{ | |
public function validate($request, $value); | |
} | |
class GetParamExistenceValidator implements ParamValidator | |
{ | |
public function validate($request, $value) | |
{ | |
return $request->isGetParamPresent($value); | |
} | |
} | |
class PostParamExistenceValidator implements ParamValidator | |
{ | |
public function validate($request, $value) | |
{ | |
return $request->isPostParamPresent($value); | |
} | |
} | |
class PutParamExistenceValidator implements ParamValidator | |
{ | |
public function validate($request, $value) | |
{ | |
return $request->isPutParamPresent($value); | |
} | |
} | |
class DeleteParamExistenceValidator implements ParamValidator | |
{ | |
public function validate($request, $value) | |
{ | |
return $request->isDeleteParamPresent($value); | |
} | |
} | |
class PolymorphismTest extends MethodCallTest | |
{ | |
public function __construct() | |
{ | |
parent::__construct(); | |
$validators = array( | |
'get' => new GetParamExistenceValidator(), | |
'post' => new PostParamExistenceValidator(), | |
'put' => new PutParamExistenceValidator(), | |
'delete' => new DeleteParamExistenceValidator(), | |
); | |
foreach ($this->params as &$param) { | |
$param[0] = $validators[$param[0]]; | |
} | |
unset($param); | |
} | |
public function getName() | |
{ | |
return 'Polymorphism'; | |
} | |
protected function test() | |
{ | |
for ($i = 0; $i < $this->loops; $i++) { | |
foreach ($this->params as $param) { | |
$validator = $param[0]; | |
$name = $param[1]; | |
$exists = $validator->validate($this->request, $name); | |
} | |
} | |
} | |
} | |
//// Run tests | |
$tester = new Tester(TEST_CALLS); | |
$tester->test(new IfElseTest()); | |
$tester->test(new SwitchTest()); | |
$tester->test(new VariableFunctionsTest()); | |
$tester->test(new AnonymousFunctionsTest()); | |
$tester->test(new CallUserFuncTest()); | |
$tester->test(new EvalTest()); | |
$tester->test(new ReflectionTest()); | |
$tester->test(new PolymorphismTest()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment