<?php
function arrayof_foo(Foo[] $fooze) {
foreach ($fooze as $foo) {
$foo->bar();
}
}
function user_instanceof_foo(array $fooze) {
foreach ($fooze as $foo) {
if ($foo instanceof Foo) {
$foo->bar();
}
}
}
function user_filter_foo(array $fooze) {
foreach (array_filter($fooze, function ($object) {
return $object instanceof Foo;
}) as $foo) {
$foo->bar();
}
}
function user_arrays(array $arrays) {
foreach ($arrays as $array) {
if (is_array($array)) {
continue;
}
}
}
function arrayof_arrays(array[] $arrays) {
foreach ($arrays as $array) {
continue;
}
}
function user_callables(array $callables) {
foreach ($callables as $callable) {
if (is_callable($callable)) {
$callable();
}
}
}
function arrayof_callables(callable[] $callables) {
foreach ($callables as $callable) {
$callable();
}
}
function user_interfaces(ArrayOfFoo $fooArray) {
foreach ($fooArray as $i => $foo) {
$foo->bar();
}
}
abstract class ArrayOf implements ArrayAccess, Iterator, Countable {
protected $type = null;
protected $data = [];
protected $index = 0;
public function __construct() {
if (is_null($this->type)) { throw new Exception('Extending classes must specify a type.'); }
}
public function offsetSet($offset, $value) {
if ($value instanceof $this->type) {
$this->data[$offset] = $value;
} else {
$type = is_object($value) ? get_class($value) : gettype($value);
throw new UnexpectedValueException(
sprintf('Value must be of type %s, %s given.', $this->type, $type)
);
}
}
public function offsetExists($offset) { return isset($this->data[$offset]); }
public function offsetGet($offset) { return $this->data[$offset]; }
public function offsetUnset($offset) { unset($this->data[$offset]); }
public function current() { return $this->data[$this->index]; }
public function next() { ++$this->index; }
public function key() { return $this->index; }
public function valid() { return isset($this->data[$this->index]); }
public function rewind() { $this->index = 0; }
public function count() { return count($this->data); }
}
class ArrayOfFoo extends ArrayOf { protected $type = 'Foo'; }
class Foo { public function bar() { return __METHOD__; } }
$ctors = [];
$timers = [];
$fooze = [];
$arrays = [];
$callables = [];
$result = [];
$max = $argv[1] ? $argv[1] : 1000;
$start = microtime(true);
while (count($fooze) < $max) {
$fooze[] = new Foo();
}
$ctors["native"] = microtime(true)-$start;
while (count($arrays) < $max) {
$arrays[] = array();
$callables[] = function(){};
}
$start = microtime(true);
$fooArray = new ArrayOfFoo;
for ($i=0; count($fooArray) < $max; $i++) {
$fooArray[$i] = new Foo;
}
$ctors["user"] = microtime(true)-$start;
$totalRuns = 500;
$timers = [
"user_instanceof_foo" => $fooze,
"user_filter_foo" => $fooze,
"arrayof_foo" => $fooze,
"user_arrays" => $arrays,
"arrayof_arrays" => $arrays,
"user_callables" => $callables,
"arrayof_callables" => $callables,
"user_interfaces" => $fooArray
];
for($i = 0; $i < $totalRuns; ++$i){
foreach($timers as $callable => $arg){
$alpha = microtime(true);
$callable($arg);
$result[$callable] += microtime(true) - $alpha;
}
}
$result = array_map(function ($v) use($totalRuns) {
return $v / $totalRuns;
}, $result);
asort($result, SORT_NUMERIC);
asort($ctors, SORT_NUMERIC);
printf("constructors [not very reliable timings]:\n");
foreach ($ctors as $name => $time) {
printf("%-30s\t%.8f\n", $name, $time);
}
printf("\n");
printf("tests:\n");
foreach ($result as $name => $time) {
printf("%-30s\t%.8f\n",
str_replace("_", " ", $name), $time);
}
?>
Note: each test function is run 500 times, averages provided
[joe@fiji php-src]$ sapi/cli/php -n -dmemory_limit=2G perf.php 10
constructors [not very reliable timings]:
native 0.00001502
user 0.00003695
tests:
arrayof arrays 0.00000122
arrayof callables 0.00000202
user arrays 0.00000209
arrayof foo 0.00000223
user instanceof foo 0.00000227
user callables 0.00000275
user filter foo 0.00000468
user interfaces 0.00000835
[joe@fiji php-src]$ sapi/cli/php -n -dmemory_limit=2G perf.php 100
constructors [not very reliable timings]:
native 0.00004292
user 0.00014400
tests:
arrayof arrays 0.00000708
arrayof callables 0.00001340
user arrays 0.00001344
arrayof foo 0.00001379
user instanceof foo 0.00001475
user callables 0.00002122
user filter foo 0.00003038
user interfaces 0.00006573
[joe@fiji php-src]$ sapi/cli/php -n -dmemory_limit=2G perf.php 1000
constructors [not very reliable timings]:
native 0.00034094
user 0.00122619
tests:
arrayof arrays 0.00007181
arrayof foo 0.00013031
user arrays 0.00013081
arrayof callables 0.00013340
user instanceof foo 0.00014088
user callables 0.00020693
user filter foo 0.00028824
user interfaces 0.00066317
[joe@fiji php-src]$ sapi/cli/php -n -dmemory_limit=2G perf.php 10000
constructors [not very reliable timings]:
native 0.00346088
user 0.01473308
tests:
arrayof arrays 0.00235372
arrayof foo 0.00243142
user arrays 0.00320780
arrayof callables 0.00378044
user callables 0.00433458
user filter foo 0.00465060
user instanceof foo 0.00549773
user interfaces 0.00862223
[joe@fiji php-src]$ sapi/cli/php -n -dmemory_limit=2G perf.php 100000
constructors [not very reliable timings]:
native 0.03715611
user 0.18054104
tests:
arrayof foo 0.03434128
user arrays 0.03928255
arrayof arrays 0.04027043
arrayof callables 0.05607406
user filter foo 0.05802278
user callables 0.05824624
user instanceof foo 0.06152818
user interfaces 0.13526678
This needs to be implemented! Currently Using __call() magic methods to use reflections to check doc types & use regex to get type definitions in the @method annotation for arguments to manually check for the values passed by a given array. would be nice to have this implemented in a supported language version!.