Skip to content

Instantly share code, notes, and snippets.

@DWand
Created January 3, 2015 23:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DWand/54ae49470ee8557432a3 to your computer and use it in GitHub Desktop.
Save DWand/54ae49470ee8557432a3 to your computer and use it in GitHub Desktop.
Benchmark for a method calling based on variable value in PHP
<?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