├── .gitignore
├── benchmark_str_contains_vs_strpos.php
├── benchmark_file_exists_vs_is_file.php
├── benchmark_array_key_exists_vs_isset.php
├── benchmark_env_vs_constant.php
├── LICENSE
├── example2.php
├── reference_vs_no_reference.php
├── benchmark_multiplecomparison_strpos.php
├── benchmark_echo_vs_strings.php
├── benchmark_count_isarray.php
├── benchmark_is_array_countable.php
├── benchmark_hash.php
├── benchmark_arraymap_foreach.php
├── benchmark_eval.php
├── benchmark_byval_vs_byref.php
├── benchmark_array_merge_vs_plus.php
├── benchmark_const_variable_literal.php
├── benchmark_is_array_type.php
├── benchmark_types_arguments.php
├── benchmark_isset_vs_at.php
├── benchmark_serialization.php
├── json_vs_serialize.php
├── benchmark_array_vs_object.php
├── Collection.php
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/
2 |
--------------------------------------------------------------------------------
/benchmark_str_contains_vs_strpos.php:
--------------------------------------------------------------------------------
1 | 'abc','b'=>'bcd','c'=>'def',20,30,40];
15 |
16 |
17 |
18 |
19 | // **********************************************************************************
20 | $t1=microtime(true);
21 | for($i=0;$i<$instances;$i++) {
22 | $r=file_exists(__FILE__);
23 | $r1=file_exists('none.none');
24 | }
25 | $t2=microtime(true);
26 | $table['file_exists']=$t2-$t1;
27 | // **********************************************************************************
28 | $t1=microtime(true);
29 | for($i=0;$i<$instances;$i++) {
30 | $r=is_file(__FILE__);
31 | $r1=is_file('none.none');
32 |
33 | }
34 | $t2=microtime(true);
35 | $table['is_file']=$t2-$t1;
36 | echo \mapache_commons\Collection::generateTable($table);
--------------------------------------------------------------------------------
/benchmark_array_key_exists_vs_isset.php:
--------------------------------------------------------------------------------
1 | 'abc','b'=>'bcd','c'=>'def',20,30,40];
15 |
16 |
17 |
18 | // **********************************************************************************
19 | $t1=microtime(true);
20 | for($i=0;$i<$instances;$i++) {
21 | $r=array_key_exists('repeated',$array1);
22 | $r=array_key_exists('repeatedxxx',$array1);
23 | }
24 | $t2=microtime(true);
25 | $table['array_key_exists']=$t2-$t1;
26 | // **********************************************************************************
27 | $t1=microtime(true);
28 | for($i=0;$i<$instances;$i++) {
29 | $r=isset($array1['repeated']);
30 | $r=isset($array1['repeatedxxx']);
31 | }
32 | $t2=microtime(true);
33 | $table['isset']=$t2-$t1;
34 | echo \mapache_commons\Collection::generateTable($table);
--------------------------------------------------------------------------------
/benchmark_env_vs_constant.php:
--------------------------------------------------------------------------------
1 | null,'dateInvoice'=>null,'invoiceDetails'=>[]];
21 | }
22 | function InvoiceDetailFactory() {
23 | return ['idInvoiceDetail'=>null,'idProduct'=>null,'price'=>null];
24 | }
25 |
26 | $obj=InvoiceFactory();
27 | $obj['invoiceDetails']=[InvoiceDetailFactory(),InvoiceDetailFactory()];
28 |
29 |
30 |
31 |
32 | $obj=new Invoice();
33 | $obj->dateInvoice=new DateTime();
34 | $obj->invoiceDetails=[new InvoiceDetail(),new InvoiceDetail()];
35 |
36 | var_dump(unserialize(serialize($obj)));
37 | echo "
";
38 |
39 | $obj2=objectToObject(json_decode( json_encode($obj)),'Invoice');
40 |
41 | var_dump( $obj2);
42 |
43 |
44 | function objectToObject($instance, $className) {
45 | return unserialize(sprintf(
46 | 'O:%d:"%s"%s',
47 | strlen($className),
48 | $className,
49 | strstr(strstr(serialize($instance), '"'), ':')
50 | ));
51 | }
52 |
--------------------------------------------------------------------------------
/reference_vs_no_reference.php:
--------------------------------------------------------------------------------
1 | Reference vs No Reference";
11 | echo "
It tests the performance between a function that returns a value by reference versus the use of return
";
12 |
13 | $result=[];
14 |
15 | $t1=microtime(true);
16 |
17 | $array=['a1'=>1,'a2'=>'aaaa','a3'=>50.56];
18 |
19 | for($i=0;$i<1000000;$i++) {
20 | reference($array);
21 | }
22 |
23 |
24 |
25 | $t2=microtime(true);
26 | $result['Reference']=$t2-$t1;
27 |
28 |
29 | $t1=microtime(true);
30 |
31 | $array=['a1'=>1,'a2'=>'aaaa','a3'=>50.56];
32 |
33 | for($i=0;$i<1000000;$i++) {
34 | $array=noReference($array);
35 | }
36 | $t2=microtime(true);
37 | $result['No Reference']=$t2-$t1;
38 |
39 | $result['Speed of Reference %']= 100-( $result['Reference']*100 / $result['No Reference']);
40 |
41 | echo \mapache_commons\Collection::generateTable($result);
42 |
43 | function reference(&$array) {
44 | $array['a1']=2;
45 | $array['a2']='bbbb';
46 | $array['a4']=55555;
47 | }
48 | function noReference($array) {
49 | $array['a1']=2;
50 | $array['a2']='bbbb';
51 | $array['a4']=55555;
52 | return $array;
53 | }
--------------------------------------------------------------------------------
/benchmark_multiplecomparison_strpos.php:
--------------------------------------------------------------------------------
1 | echo:
";
13 | // **********************************************************************************
14 | $t1=microtime(true);
15 | for($i=0;$i<$instances;$i++) {
16 | echo 'hello world 123456789012345678901234567890';
17 | }
18 | $t2=microtime(true);
19 |
20 | $table['echo']=$t2-$t1;
21 | echo "
concat:
";
22 | // **********************************************************************************
23 | $t1=microtime(true);
24 | $str='';
25 | for($i=0;$i<$instances;$i++) {
26 | $str.='hello world 123456789012345678901234567890';
27 | }
28 | echo $str;
29 | // note: $r=eval('ping("pong");'); return null
30 | // note: $r=eval('return ping("pong");'); return 'pong'
31 | $t2=microtime(true);
32 | $table['concat']=$t2-$t1;
33 | echo "
implode:
";
34 | // **********************************************************************************
35 | $t1=microtime(true);
36 | $str=[];
37 | for($i=0;$i<$instances;$i++) {
38 | $str[]='hello world 123456789012345678901234567890';
39 | }
40 | echo implode('',$str);
41 | // note: $r=eval('ping("pong");'); return null
42 | // note: $r=eval('return ping("pong");'); return 'pong'
43 | $t2=microtime(true);
44 | $table['implode']=$t2-$t1;
45 | echo \mapache_commons\Collection::generateTable($table);
--------------------------------------------------------------------------------
/benchmark_count_isarray.php:
--------------------------------------------------------------------------------
1 | 'abc','b'=>'bcd','c'=>'def',20,30,40];
16 | $array2=['repeated'=>'abc','d'=>'abc2','e'=>'bcd2','f'=>'def2',50,60,70];
17 | $noarray=20;
18 |
19 | // **********************************************************************************
20 | $t1=microtime(true);
21 | for($i=0;$i<$instances;$i++) {
22 | $r=@count($array1);
23 | $r=@count($noarray);
24 | }
25 | $t2=microtime(true);
26 | $table['count']=$t2-$t1;
27 | // **********************************************************************************
28 | $t1=microtime(true);
29 | for($i=0;$i<$instances;$i++) {
30 | $r=is_array($array1)? count($array1) : null;
31 | $r=is_array($noarray)? count($noarray) : null;
32 | }
33 | $t2=microtime(true);
34 | $table['is_array count']=$t2-$t1;
35 | // **********************************************************************************
36 | $t1=microtime(true);
37 | for($i=0;$i<$instances;$i++) {
38 | is_array($array1) and $r=count($array1);
39 | is_array($noarray) and $r=count($noarray);
40 | }
41 | $t2=microtime(true);
42 | $table['is_array count 2']=$t2-$t1;
43 | // **********************************************************************************
44 |
45 |
46 | echo \mapache_commons\Collection::generateTable($table);
--------------------------------------------------------------------------------
/benchmark_is_array_countable.php:
--------------------------------------------------------------------------------
1 | 'abc','b'=>'bcd','c'=>'def',20,30,40];
16 | $array2=['repeated'=>'abc','d'=>'abc2','e'=>'bcd2','f'=>'def2',50,60,70];
17 | $noarray=20;
18 |
19 | // **********************************************************************************
20 | $t1=microtime(true);
21 | for($i=0;$i<$instances;$i++) {
22 | $r=is_countable($array1);
23 | $r=is_countable($noarray);
24 | }
25 | $t2=microtime(true);
26 | $table['is_countable']=$t2-$t1;
27 | // **********************************************************************************
28 | $t1=microtime(true);
29 | for($i=0;$i<$instances;$i++) {
30 | $r=is_array($array1)? count($array1) : null;
31 | $r=is_array($noarray)? count($noarray) : null;
32 | }
33 | $t2=microtime(true);
34 | $table['is_array count']=$t2-$t1;
35 | // **********************************************************************************
36 | $t1=microtime(true);
37 | for($i=0;$i<$instances;$i++) {
38 | is_array($array1) and $r=count($array1);
39 | is_array($noarray) and $r=count($noarray);
40 | }
41 | $t2=microtime(true);
42 | $table['is_array count 2']=$t2-$t1;
43 | // **********************************************************************************
44 |
45 |
46 | echo \mapache_commons\Collection::generateTable($table);
--------------------------------------------------------------------------------
/benchmark_hash.php:
--------------------------------------------------------------------------------
1 | Hash speed ($instances instances)";
14 | echo "It tests the performance of hash
";
15 |
16 |
17 | $data = "";
18 | for($i = 0; $i < 1500; $i++) {
19 | $data .= sha1("H:k - $i - k:H");
20 | }
21 |
22 | $res = [];
23 |
24 |
25 | foreach (hash_algos() as $algo) {
26 | $time = microtime(1);
27 |
28 | for($i=0;$i<$instances;$i++) {
29 | $hash = hash($algo, $data);
30 | }
31 | $time = (microtime(1) - $time) * 1000;
32 | $length = strlen($hash);
33 |
34 | $res[(string)$time][] = [
35 | 'format' => 'HEX',
36 | "algo" => $algo,
37 | "length" => $length,
38 | "time" => $time
39 | ];
40 |
41 | $time = microtime(1);
42 | for($i=0;$i<$instances;$i++) {
43 | $hash=hash($algo, $data, 1);
44 | }
45 | $length = strlen($hash);
46 | $time = (microtime(1) - $time) * 1000;
47 |
48 | $res[(string)$time][] = [
49 | 'format' => 'RAW',
50 | 'algo' => $algo,
51 | "length" => $length,
52 | "time" => $time
53 | ];
54 | }
55 |
56 | ksort($res);
57 | $i = 0;
58 |
59 |
60 | $final=[];
61 |
62 | foreach($res as $time=>$data) {
63 |
64 | $final[]=$data[0];
65 | }
66 |
67 | echo \mapache_commons\Collection::generateTable($final);
68 | ?>
--------------------------------------------------------------------------------
/benchmark_arraymap_foreach.php:
--------------------------------------------------------------------------------
1 | 'abc','b'=>'bcd','c'=>'def',20,30,40];
15 | $array2=['repeated'=>'abc','d'=>'abc2','e'=>'bcd2','f'=>'def2',50,60,70];
16 |
17 | function foreachMerge(&$array1, &$array2) {
18 | $tmp=$array1;
19 | foreach($array2 as $k=>$v) {
20 | $tmp[$k] = $v;
21 | }
22 | return $tmp;
23 | }
24 |
25 |
26 | // **********************************************************************************
27 | $t1=microtime(true);
28 | for($i=0;$i<$instances;$i++) {
29 | $r=array_merge($array1,$array2);
30 | }
31 | $t2=microtime(true);
32 | $table['array_merge']=$t2-$t1.' ('.count($r).')';
33 | // **********************************************************************************
34 | $t1=microtime(true);
35 | for($i=0;$i<$instances;$i++) {
36 | $r=array_replace($array1,$array2);
37 | }
38 | $t2=microtime(true);
39 | $table['array_replace']=$t2-$t1.' ('.count($r).')';
40 | // **********************************************************************************
41 | $t1=microtime(true);
42 | for($i=0;$i<$instances;$i++) {
43 | $r= $array1 + $array2;
44 | }
45 | $t2=microtime(true);
46 | $table['plus']=$t2-$t1.' ('.count($r).')';
47 | // **********************************************************************************
48 | $t1=microtime(true);
49 | for($i=0;$i<$instances;$i++) {
50 | $r= foreachMerge($array1,$array2);
51 | }
52 | $t2=microtime(true);
53 | $table['foreach']=$t2-$t1.' ('.count($r).')';
54 |
55 | echo \mapache_commons\Collection::generateTable($table);
--------------------------------------------------------------------------------
/benchmark_const_variable_literal.php:
--------------------------------------------------------------------------------
1 | 'abc','b'=>'bcd','c'=>'def',20,30,40];
16 | $array2=['repeated'=>'abc','d'=>'abc2','e'=>'bcd2','f'=>'def2',50,60,70];
17 | $noarray=20;
18 |
19 | // **********************************************************************************
20 | $t1=microtime(true);
21 | for($i=0;$i<$instances;$i++) {
22 | $r=is_countable($array1);
23 | $r=is_countable($noarray);
24 | }
25 | $t2=microtime(true);
26 | $table['is_countable']=$t2-$t1;
27 | // **********************************************************************************
28 | $t1=microtime(true);
29 | for($i=0;$i<$instances;$i++) {
30 | $r=is_array($array1);
31 | $r=is_array($noarray);
32 | }
33 | $t2=microtime(true);
34 | $table['is_array count']=$t2-$t1;
35 | // **********************************************************************************
36 | $t1=microtime(true);
37 | for($i=0;$i<$instances;$i++) {
38 | $r=gettype($array1);
39 | $r=gettype($noarray);
40 | }
41 | $t2=microtime(true);
42 | $table['gettytpe']=$t2-$t1;
43 | // **********************************************************************************
44 | // **********************************************************************************
45 | $t1=microtime(true);
46 | for($i=0;$i<$instances;$i++) {
47 | $r=get_debug_type($array1);
48 | $r=get_debug_type($noarray);
49 | }
50 | $t2=microtime(true);
51 | $table['get_debug_type']=$t2-$t1;
52 | // **********************************************************************************
53 |
54 |
55 | echo \mapache_commons\Collection::generateTable($table);
--------------------------------------------------------------------------------
/benchmark_types_arguments.php:
--------------------------------------------------------------------------------
1 | pack($input);
73 | }
74 | $t2 = microtime(true);
75 | $t3 = microtime(true);
76 | for ($i = 0; $i < $instances; $i++) {
77 | $b=$packer->unpack($ser);
78 | }
79 | $t4 = microtime(true);
80 | $table['packer->pack (msgpack)'] = $t2 - $t1;
81 | $tableunser['packer->unpack (msgpack)'] = $t4 - $t3;
82 | $tablesize['packer->pack (msgpack)'] = strlen($ser);
83 | $tablecomp['packer->pack (msgpack)'] = ($b===$input)?'yes':'no';
84 |
85 |
86 | echo "Serialize: (in seconds less is better)
";
87 | echo \mapache_commons\Collection::generateTable($table,true,true);
88 | echo "De-serialize: (in seconds less is better)
";
89 | echo \mapache_commons\Collection::generateTable($tableunser,true,true);
90 | echo "Size: (in bytes less is better)
";
91 | echo \mapache_commons\Collection::generateTable($tablesize,true,true);
92 | echo "Input is equals to output: (no means error)
";
93 | echo \mapache_commons\Collection::generateTable($tablecomp,true);
94 | echo "
";
95 | echo "
";
96 |
--------------------------------------------------------------------------------
/json_vs_serialize.php:
--------------------------------------------------------------------------------
1 | Json vs Serialize ($instances instances)";
13 | echo "It tests the performance of hash
";
14 | $result=[];
15 |
16 |
17 | $data=['field1'=>"hello",'field2'=>450,'field3'=>['field4'=>'hello','field5'=>450]];
18 |
19 |
20 |
21 | // *********** json_encode
22 | $t1=microtime(true);
23 | for($i=0;$i<$instances;$i++) {
24 | $jsonEnc=json_encode($data);
25 | }
26 | $t2=microtime(true);
27 | $result[]=['type'=>'json_encode array','time'=> ($t2-$t1)*100000];
28 | // *********** serialize
29 | $t1=microtime(true);
30 | for($i=0;$i<$instances;$i++) {
31 | $ser=serialize($data);
32 | }
33 | $t2=microtime(true);
34 | $result[]=['type'=>'serialize array','time'=> ($t2-$t1)*100000];
35 |
36 | // *********** json_decode
37 | $t1=microtime(true);
38 | for($i=0;$i<$instances;$i++) {
39 | $r1=json_decode($jsonEnc,true);
40 | }
41 | $t2=microtime(true);
42 | $result[]=['type'=>'json_decode array','time'=> ($t2-$t1)*100000];
43 | // *********** serialize
44 | $t1=microtime(true);
45 | for($i=0;$i<$instances;$i++) {
46 | $r1=unserialize($ser);
47 | }
48 | $t2=microtime(true);
49 | $result[]=['type'=>'unserialize array','time'=> ($t2-$t1)*100000];
50 |
51 | $data=new stdClass();
52 | $data->field1="hello";
53 | $data->field2=450;
54 | $data->field3=new stdClass();
55 | $data->field3->field4="hello";
56 | $data->field3->field5=450;
57 |
58 | // *********** json_encode
59 | $t1=microtime(true);
60 | for($i=0;$i<$instances;$i++) {
61 | $jsonEnc=json_encode($data);
62 | }
63 | $t2=microtime(true);
64 | $result[]=['type'=>'json_encode object stdclass','time'=> ($t2-$t1)*100000];
65 | // *********** serialize
66 | $t1=microtime(true);
67 | for($i=0;$i<$instances;$i++) {
68 | $ser=serialize($data);
69 | }
70 | $t2=microtime(true);
71 | $result[]=['type'=>'serialize object stdclass','time'=> ($t2-$t1)*100000];
72 |
73 | // *********** json_decode
74 | $t1=microtime(true);
75 | for($i=0;$i<$instances;$i++) {
76 | $r1=json_decode($jsonEnc);
77 | }
78 | $t2=microtime(true);
79 | $result[]=['type'=>'json_decode object stdclass','time'=> ($t2-$t1)*100000];
80 | // *********** serialize
81 | $t1=microtime(true);
82 | for($i=0;$i<$instances;$i++) {
83 | $r1=unserialize($ser);
84 | }
85 | $t2=microtime(true);
86 | $result[]=['type'=>'unserialize object stdclass','time'=> ($t2-$t1)*100000];
87 |
88 |
89 | $data=new MyClass();
90 | $data->field1="hello";
91 | $data->field2=450;
92 | $data->field3=new MyClass2();
93 | $data->field3->field4="hello";
94 | $data->field3->field5=450;
95 |
96 | // *********** json_encode
97 | $t1=microtime(true);
98 | for($i=0;$i<$instances;$i++) {
99 | $jsonEnc=json_encode($data);
100 | }
101 | $t2=microtime(true);
102 | $result[]=['type'=>'json_encode object','time'=> ($t2-$t1)*100000];
103 | // *********** serialize
104 | $t1=microtime(true);
105 | for($i=0;$i<$instances;$i++) {
106 | $ser=serialize($data);
107 | }
108 | $t2=microtime(true);
109 | $result[]=['type'=>'serialize object','time'=> ($t2-$t1)*100000];
110 |
111 | // *********** json_decode
112 | $t1=microtime(true);
113 | for($i=0;$i<$instances;$i++) {
114 | $r1=json_decode($jsonEnc);
115 | }
116 | $t2=microtime(true);
117 | $result[]=['type'=>'json_decode object','time'=> ($t2-$t1)*100000];
118 | // *********** serialize
119 | $t1=microtime(true);
120 | for($i=0;$i<$instances;$i++) {
121 | $r1=unserialize($ser);
122 | }
123 | $t2=microtime(true);
124 | $result[]=['type'=>'unserialize object','time'=> ($t2-$t1)*100000];
125 |
126 |
127 |
128 |
129 | echo \mapache_commons\Collection::generateTable($result);
130 |
131 | class MyClass {
132 | var $field1;
133 | var $field2;
134 | var $field3;
135 | }
136 | class MyClass2 {
137 | var $field4;
138 | var $field5;
139 | }
--------------------------------------------------------------------------------
/benchmark_array_vs_object.php:
--------------------------------------------------------------------------------
1 | hello = $hello;
25 | $this->second = $second;
26 | $this->third = $third;
27 | }
28 | }
29 | class DummyClass2 {
30 | public $hello;
31 | public $second;
32 | public $third;
33 | }
34 |
35 | class DummyClass3 {
36 | protected $hello;
37 | protected $second;
38 | protected $third;
39 |
40 | /**
41 | * @return mixed
42 | */
43 | public function getHello()
44 | {
45 | return $this->hello;
46 | }
47 |
48 | /**
49 | * @param mixed $hello
50 | */
51 | public function setHello($hello): void
52 | {
53 | $this->hello = $hello;
54 | }
55 |
56 | /**
57 | * @return mixed
58 | */
59 | public function getSecond()
60 | {
61 | return $this->second;
62 | }
63 |
64 | /**
65 | * @param mixed $second
66 | */
67 | public function setSecond($second): void
68 | {
69 | $this->second = $second;
70 | }
71 |
72 | /**
73 | * @return mixed
74 | */
75 | public function getThird()
76 | {
77 | return $this->third;
78 | }
79 |
80 | /**
81 | * @param mixed $third
82 | */
83 | public function setThird($third): void
84 | {
85 | $this->third = $third;
86 | }
87 |
88 |
89 | }
90 |
91 | class DummyClass3Magic {
92 | protected $hello;
93 | protected $second;
94 | protected $third;
95 |
96 | public function __get($property) {
97 | return $this->$property;
98 | }
99 |
100 | public function __set($property, $value) {
101 | $this->$property = $value;
102 | }
103 |
104 |
105 | }
106 |
107 | //#[ArrayShape(['hello' => "", 'second' => ""])]
108 | function factory($hello, $second,$third) {
109 | return ['hello'=>$hello,'second'=>$second,'third'=>$third];
110 | }
111 | function factoryNumeric($hello, $second,$third) {
112 | return [$hello,$second,$third];
113 | }
114 | // **********************************************************************************
115 | $list=[];
116 | $t1=microtime(true);
117 | for($i=0;$i<$instances;$i++) {
118 | $dummy=['world',0,20.3];
119 | $nothing=$dummy[1];
120 | $list[]=$dummy;
121 | }
122 | $t2=microtime(true);
123 | $table['array numeric no factory']=$t2-$t1;
124 |
125 | // **********************************************************************************
126 | $list=[];
127 | $t1=microtime(true);
128 | for($i=0;$i<$instances;$i++) {
129 | $dummy=['hello'=>'world','second'=>0,'third'=>20.3];
130 | $nothing=$dummy['second'];
131 | $list[]=$dummy;
132 | }
133 | $t2=microtime(true);
134 | $table['array no factory']=$t2-$t1;
135 | // **********************************************************************************
136 | $list=[];
137 | $t1=microtime(true);
138 | for($i=0;$i<$instances;$i++) {
139 | $dummy=factoryNumeric('world',0,20.3);
140 | $nothing=$dummy[1];
141 | $list[]=$dummy;
142 | }
143 | $t2=microtime(true);
144 | $table['array numeric factory']=$t2-$t1;
145 | // **********************************************************************************
146 | $list=[];
147 | $t1=microtime(true);
148 | for($i=0;$i<$instances;$i++) {
149 | $dummy=factory('world',0,20.3);
150 | $nothing=$dummy['second'];
151 | $list[]=$dummy;
152 | }
153 | $t2=microtime(true);
154 | $table['array factory']=$t2-$t1;
155 | // **********************************************************************************
156 | $list=[];
157 | $t1=microtime(true);
158 | for($i=0;$i<$instances;$i++) {
159 | $dummyObj=new DummyClass('world',0,20.3);
160 | $nothing=$dummyObj->second;
161 | $list[]=$dummyObj;
162 | }
163 | $t2=microtime(true);
164 | $table['object constructor']=$t2-$t1;
165 |
166 | // **********************************************************************************
167 | $list=[];
168 | $t1=microtime(true);
169 | for($i=0;$i<$instances;$i++) {
170 | $dummyObj=new DummyClass2();
171 | $dummyObj->hello='world';
172 | $dummyObj->second=0;
173 | $dummyObj->third=20.3;
174 | $nothing=$dummyObj->second;
175 | $list[]=$dummyObj;
176 | }
177 | $t2=microtime(true);
178 | $table['object no constructor']=$t2-$t1;
179 | // **********************************************************************************
180 | $list=[];
181 | $t1=microtime(true);
182 | for($i=0;$i<$instances;$i++) {
183 | $dummyObj=new DummyClass3();
184 | $dummyObj->setHello('world');
185 | $dummyObj->setSecond(0);
186 | $dummyObj->setThird(20.3);
187 | $nothing=$dummyObj->getSecond();
188 | $list[]=$dummyObj;
189 | }
190 | $t2=microtime(true);
191 | $table['object no constructor setter/getter']=$t2-$t1;
192 |
193 | // **********************************************************************************
194 | $list=[];
195 | $t1=microtime(true);
196 | for($i=0;$i<$instances;$i++) {
197 | $dummyObj=new DummyClass3Magic();
198 | $dummyObj->hello='world';
199 | $dummyObj->second=0;
200 | $dummyObj->third=20.3;
201 | $nothing=$dummyObj->second;
202 | $list[]=$dummyObj;
203 | }
204 | $t2=microtime(true);
205 | $table['object no constructor setter/getter (magic)']=$t2-$t1;
206 |
207 |
208 | // **********************************************************************************
209 | $list=[];
210 | $t1=microtime(true);
211 | for($i=0;$i<$instances;$i++) {
212 | $dummyObj=new stdClass();
213 | $dummyObj->hello='world';
214 | $dummyObj->second=0;
215 | $dummyObj->third=20.3;
216 | $nothing=$dummyObj->second;
217 | $list[]=$dummyObj;
218 | }
219 | $t2=microtime(true);
220 | $table['object no constructor stdClass']=$t2-$t1;
221 |
222 | $min=min($table);
223 |
224 | echo \mapache_commons\Collection::generateTable($table);
225 |
226 | $tablePercent=[];
227 | foreach($table as $k=>$v) {
228 | $tablePercent[$k]=round($v/$min*100 - 100,2).'%';
229 | }
230 |
231 | echo \mapache_commons\Collection::generateTable($tablePercent);
--------------------------------------------------------------------------------
/Collection.php:
--------------------------------------------------------------------------------
1 | ";
108 | }
109 | if ($css === true) {
110 | $html = '';
128 | } else {
129 | $html = '';
130 | }
131 | $html .= '';
132 | // header row
133 | $html .= '';
134 | foreach ($array[0] as $key => $value) {
135 | $html .= '| ' . htmlspecialchars($key) . ' | ';
136 | }
137 | $html .= '
';
138 |
139 | // data rows
140 | foreach ($array as $key => $value) {
141 | $html .= '';
142 | foreach ($value as $key2 => $value2) {
143 | if (is_array($value2)) {
144 | $html .= '| ' . self::generateTable($value2) . ' | ';
145 | } else {
146 | if($percentage) {
147 | $p=round($value2/$min*100 ,2).'%';
148 | $html .= '' . htmlspecialchars($value2) .' '.$p.' | ';
149 | } else {
150 | $html .= '' . htmlspecialchars($value2) .' | ';
151 | }
152 |
153 | }
154 |
155 | }
156 | $html .= '
';
157 | }
158 |
159 | // finish table and return it
160 |
161 | $html .= '
';
162 | return $html;
163 | }
164 |
165 | /**
166 | * Split a string using an opening and closing tag.
167 | * Example:
168 | * Collection::splitOpeningClosing("a(B,C,D)e(F,G,H)"); // ['a','B,C,D','e','F,G,H']
169 | * Collection::splitOpeningClosing("a(B,C,D)e(F,G,H)i"); // ['a','B,C,D','e','F,G,H','i']
170 | *
171 | * @param string $text input text to separated
172 | * @param string $openingTag Opening tag
173 | * @param string $closingTag closing tag
174 | * @param int $startPosition start position (by default it is zero)
175 | * @param bool $excludeEmpty if true then it excludes all empty values.
176 | * @param bool $includeTag if true then it includes the tag.
177 | *
178 | * @return array If errror then it returns an empty array
179 | */
180 | public static function splitOpeningClosing(
181 | $text,
182 | $openingTag = '(',
183 | $closingTag = ')',
184 | $startPosition = 0,
185 | $excludeEmpty = true,
186 | $includeTag = false
187 | ) {
188 | if (!$text) {
189 | return [];
190 | }
191 | $p0 = $startPosition;
192 | $oL = strlen($openingTag);
193 | $cL = strlen($closingTag);
194 | $result = [];
195 | // starting.
196 | $even = false;
197 | while ($p0 !== false) {
198 | if (!$even) {
199 | $p1 = strpos($text, $openingTag, $p0);
200 | if ($p1 === false) {
201 | $result[] = substr($text, $p0);
202 | break;
203 | }
204 | $result[] = substr($text, $p0, $p1 - $p0);
205 | $even = true;
206 | $p0 = $p1 + $oL;
207 | } else {
208 | $p1 = strpos($text, $closingTag, $p0);
209 | if ($p1 === false) {
210 | $result[] = substr($text, $p0);
211 | break;
212 | }
213 | $result[] = $includeTag ? $openingTag . substr($text, $p0, $p1 - $p0) . $closingTag
214 | : substr($text, $p0, $p1 - $p0);
215 | $even = false;
216 | $p0 = $p1 + $cL;
217 | }
218 | }
219 | if ($excludeEmpty) {
220 | return array_values(array_filter($result, function ($value) {
221 | return $value !== "";
222 | })); // array_values for rebuild the index (array_filter deletes items but not reindex
223 | } else {
224 | return $result;
225 | }
226 | }
227 |
228 | /**
229 | * Split a string by ignoring parts of string where values are between " or '.
230 | * Example:
231 | * Collection::splitNotString('a,b,"CC,D,E",e,f' ,","); // ['a','b','CC,D,E','e','f']
232 | *
233 | * @param string $text input text
234 | * @param string $separator
235 | * @param int $offset
236 | * @param bool $excludeEmpty
237 | *
238 | * @return array
239 | */
240 | public static function splitNotString($text, $separator, $offset = 0, $excludeEmpty = true) {
241 | $p0 = $offset;
242 | $even = false;
243 | $sL = strlen($separator);
244 | $pc = null;
245 | $result = [];
246 | while ($p0 !== false) {
247 | if (!$even) {
248 | $p1 = strpos($text, $separator, $p0);
249 | $p1 = ($p1 === false) ? PHP_INT_MAX : $p1;
250 | $p2 = strpos($text, '"', $p0);
251 | $p2 = ($p2 === false) ? PHP_INT_MAX : $p2;
252 | $p3 = strpos($text, "'", $p0);
253 | $p3 = ($p3 === false) ? PHP_INT_MAX : $p3;
254 | $ptxt = min($p2, $p3);
255 | if ($p1 == PHP_INT_MAX && $ptxt == PHP_INT_MAX) {
256 | // end
257 | $result[] = substr($text, $p0);
258 | break;
259 |
260 | }
261 | if ($p1 < $ptxt) {
262 | // the next separator is a separator
263 | $result[] = substr($text, $p0, $p1 - $p0);
264 | $p0 = $p1 + $sL;
265 | } else {
266 | // the next separator is a string
267 | $pc = substr($text, $ptxt, 1); // " or '
268 | $even = true;
269 | $p0 = $ptxt + 1;
270 | }
271 | } else {
272 | // we are inside a string
273 | $p1 = strpos($text, $pc, $p0);
274 | if ($p1 === false) {
275 | // we don't found the closing tag
276 | $result[] = substr($text, $p0);
277 | break;
278 | }
279 | $result[] = substr($text, $p0, $p1 - $p0);
280 | $even = false; // and we are out of the string
281 | $p0 = $p1 + 1;
282 | }
283 | }
284 | if ($excludeEmpty) {
285 | return array_values(array_filter($result, function ($value) {
286 | return $value !== "";
287 | }));
288 | } else {
289 | return $result;
290 | }
291 | }
292 |
293 | /**
294 | * It changes the case (to lower or upper case) of the keys of an array recursively
295 | *
296 | * @param array $array input array
297 | *
298 | * @param int $case [optional] by default is CASE_LOWER
299 | * Either CASE_UPPER or
300 | * CASE_LOWER (default)
301 | *
302 | * @return array
303 | * @see https://www.php.net/manual/en/function.array-change-key-case.php
304 | */
305 | public static function arrayChangeKeyCaseRecursive($array, $case = CASE_LOWER) {
306 | return array_map(function ($item) {
307 | if (is_array($item)) {
308 | $item = self::arrayChangeKeyCaseRecursive($item);
309 | }
310 | return $item;
311 | }, array_change_key_case($array, $case));
312 | }
313 |
314 | /**
315 | * It returns the first (or all) key(s) inside an array/object in an array that matches the value of the field
316 | * Example: arraySearchField([['name'=>'john'],['name'=>'mary']],'name','mary'); // returns 1
317 | *
318 | * @param array $array input array
319 | * @param string|int $fieldName name of index of the field
320 | * @param mixed $value value to search
321 | *
322 | * @param bool $returnAll if true then it returns all matches. If false it returns the first value.
323 | *
324 | * @return int|string|bool|array return false if not found or if error.
325 | */
326 | public static function arraySearchField($array, $fieldName, $value, $returnAll = false) {
327 | $first = reset($array);
328 | $result = [];
329 | if (is_object($first)) {
330 | foreach ($array as $k => $v) {
331 | if (@$v->{$fieldName} === $value) {
332 | if ($returnAll) {
333 | $result[] = $k;
334 | } else {
335 | return $k;
336 | }
337 | }
338 | }
339 | if ($returnAll) {
340 | return $result;
341 | } else {
342 | return false;
343 | }
344 | }
345 | if (is_array($first)) {
346 | foreach ($array as $k => $v) {
347 | if (@$v[$fieldName] === $value) {
348 | if ($returnAll) {
349 | $result[] = $k;
350 | } else {
351 | return $k;
352 | }
353 | }
354 | }
355 | if ($returnAll) {
356 | return $result;
357 | } else {
358 | return false;
359 | }
360 | }
361 | return false;
362 | }
363 |
364 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP benchmarks
2 | It is a collection of PHP benchmarks. Those benchmarks are aimed to be executed in most machines without any special installation or configuration. It only requires a single library (to draw the table) and nothing else much. It doesn't require composer or any other extra component. Just download (or copy and paste) and run.
3 |
4 |
5 |
6 | ## Awards
7 |
8 | [PHP Benchmarks: Evaluate the speed of PHP running different tasks - PHP Classes](https://www.phpclasses.org/package/11893-PHP-Evaluate-the-speed-of-PHP-running-different-tasks.html)
9 |
10 |
11 |
12 | It is tested under PHP 7.4 / PHP 8.0 + 64bits + Windows 64 bits but you could download it and test it by yourself (it is the idea).
13 |
14 | ## Table of contents
15 |
16 | - [PHP benchmarks](#php-benchmarks)
17 | - [Table of contents](#table-of-contents)
18 | - [Benchmark 1, Reference vs No Reference](#benchmark-1-reference-vs-no-reference)
19 | - [Result (smaller is better)](#result-smaller-is-better)
20 | - [Bechmark 2 Hash speed](#bechmark-2-hash-speed)
21 | - [Result (short time is better)](#result-short-time-is-better)
22 | - [JSON vs Serialize](#json-vs-serialize)
23 | - [Result (less is better)](#result-less-is-better)
24 | - [DEFINE / CONST / ENV](#define--const--env)
25 | - [Result (less is better)](#result-less-is-better)
26 | - [array_map vs foreach](#array_map-vs-foreach)
27 | - [Result 7.x (less is better)](#result-7x-less-is-better)
28 | - [Result 8.x (less is better)](#result-8x-less-is-better)
29 | - [isset vs @ at](#isset-vs--at)
30 | - [Result (smaller is better)](#result-smaller-is-better)
31 | - [Type hinting](#type-hinting)
32 | - [Result (smaller is better)](#result-smaller-is-better)
33 | - [Benchmark eval](#benchmark-eval)
34 | - [Result (smaller is better)](#result-smaller-is-better)
35 | - [Benchmark count vs is_array and count](#benchmark-count-vs-is_array-and-count)
36 | - [Result (smaller is better)](#result-smaller-is-better)
37 | - [Benchmark is_array vs is_countable](#benchmark-is_array-vs-is_countable)
38 | - [Result (smaller is better)](#result-smaller-is-better)
39 | - [Benchmark array_key_exists vs isset](#benchmark-array_key_exists-vs-isset)
40 | - [Result (smaller is better)](#result-smaller-is-better)
41 | - [Benchmark str_contains vs str_pos](#benchmark-str_contains-vs-str_pos)
42 | - [Result (smaller is better)](#result-smaller-is-better)
43 | - [Benchmark file_exists vs is_file](#benchmark-file_exists-vs-is_file)
44 | - [Result (smaller is better)](#result-smaller-is-better)
45 | - [Benchmark array_merge vs others](#benchmark-array_merge-vs-others)
46 | - [Result (smaller is better)](#result-smaller-is-better)
47 |
48 | ## Benchmark 1, Reference vs No Reference
49 |
50 | Is it fast to use a reference argument or return a value?
51 |
52 | [reference_vs_no_reference.php](reference_vs_no_reference.php)
53 |
54 | ```
55 | function reference(&$array) {
56 | $array['a1']=2;
57 | $array['a2']='bbbb';
58 | $array['a4']=55555;
59 | }
60 | function noReference($array) {
61 | $array['a1']=2;
62 | $array['a2']='bbbb';
63 | $array['a4']=55555;
64 | return $array;
65 | }
66 | ```
67 |
68 | ### Result (smaller is better)
69 |
70 | | Reference | No Reference | Speed of Reference % |
71 | | :---------------------------- | :--------------- | :------------------- |
72 | | **0.06107497215271** (faster) | 0.10248017311096 | 40.403133309913 |
73 |
74 | Conclusion: Using a reference argument is faster than using an argument by value
75 |
76 | ## Bechmark 2 Hash speed
77 |
78 | We test the benchmark of the generation of hash.
79 |
80 | [benchmark_hash.php](benchmark_hash.php)
81 |
82 | HEX means that the result is resulted in HEXADECIMAL.
83 |
84 | RAW means the result is binary. Sometimes HEX=RAW.
85 |
86 |
87 |
88 | ### Result (short time is better)
89 |
90 |
91 |
92 | | format | algo | length | time |
93 | | :----- | :---------- | :----- | :-------------- |
94 | | HEX | adler32 | 8 | 4.6730041503906 |
95 | | RAW | adler32 | 4 | 4.7018527984619 |
96 | | RAW | fnv164 | 8 | 6.2000751495361 |
97 | | HEX | fnv1a32 | 8 | 6.2048435211182 |
98 | | HEX | fnv132 | 8 | 6.2098503112793 |
99 | | RAW | fnv132 | 4 | 6.2119960784912 |
100 | | HEX | fnv164 | 16 | 6.2189102172852 |
101 | | HEX | fnv1a64 | 16 | 6.2229633331299 |
102 | | RAW | fnv1a32 | 4 | 6.227970123291 |
103 | | RAW | tiger192,3 | 24 | 8.040189743042 |
104 | | RAW | tiger160,3 | 20 | 8.0409049987793 |
105 | | HEX | tiger160,3 | 40 | 8.0428123474121 |
106 | | HEX | tiger192,3 | 48 | 8.0468654632568 |
107 | | HEX | tiger128,3 | 32 | 8.0511569976807 |
108 | | RAW | tiger128,3 | 16 | 8.2709789276123 |
109 | | RAW | md4 | 16 | 8.6510181427002 |
110 | | HEX | md4 | 32 | 8.6619853973389 |
111 | | RAW | joaat | 4 | 9.3100070953369 |
112 | | HEX | joaat | 8 | 9.3538761138916 |
113 | | RAW | md5 | 16 | 10.200977325439 |
114 | | HEX | md5 | 32 | 10.215997695923 |
115 | | RAW | tiger128,4 | 16 | 10.791063308716 |
116 | | HEX | tiger160,4 | 40 | 10.793924331665 |
117 | | RAW | tiger160,4 | 20 | 10.806083679199 |
118 | | RAW | tiger192,4 | 24 | 10.81109046936 |
119 | | HEX | tiger128,4 | 32 | 10.812044143677 |
120 | | HEX | tiger192,4 | 48 | 10.833978652954 |
121 | | HEX | sha1 | 40 | 11.46388053894 |
122 | | RAW | sha1 | 20 | 11.497020721436 |
123 | | HEX | crc32c | 8 | 16.038179397583 |
124 | | RAW | crc32c | 4 | 16.067028045654 |
125 | | HEX | sha3-224 | 56 | 16.110181808472 |
126 | | RAW | sha3-224 | 28 | 16.110897064209 |
127 | | HEX | crc32b | 8 | 16.125917434692 |
128 | | RAW | crc32b | 4 | 16.162872314453 |
129 | | HEX | sha512/224 | 56 | 17.075777053833 |
130 | | HEX | sha512 | 128 | 17.086982727051 |
131 | | RAW | sha512/224 | 28 | 17.08984375 |
132 | | HEX | sha3-256 | 64 | 17.097949981689 |
133 | | RAW | sha384 | 48 | 17.104864120483 |
134 | | RAW | sha512 | 64 | 17.114877700806 |
135 | | RAW | crc32 | 4 | 17.119884490967 |
136 | | HEX | sha512/256 | 64 | 17.130136489868 |
137 | | RAW | sha512/256 | 32 | 17.167806625366 |
138 | | HEX | crc32 | 8 | 17.171859741211 |
139 | | HEX | sha384 | 96 | 17.177820205688 |
140 | | HEX | haval160,3 | 40 | 17.213106155396 |
141 | | RAW | haval160,3 | 20 | 17.232179641724 |
142 | | HEX | haval128,3 | 32 | 17.246961593628 |
143 | | HEX | haval192,3 | 48 | 17.338037490845 |
144 | | RAW | haval128,3 | 16 | 17.502069473267 |
145 | | RAW | haval256,3 | 32 | 17.529964447021 |
146 | | RAW | haval224,3 | 28 | 17.548799514771 |
147 | | RAW | haval192,3 | 24 | 17.639875411987 |
148 | | HEX | haval224,3 | 56 | 17.678022384644 |
149 | | HEX | haval256,3 | 64 | 17.735958099365 |
150 | | HEX | ripemd256 | 64 | 20.03002166748 |
151 | | RAW | ripemd256 | 32 | 20.137071609497 |
152 | | RAW | ripemd128 | 16 | 20.437002182007 |
153 | | HEX | ripemd128 | 32 | 20.43890953064 |
154 | | HEX | sha3-384 | 96 | 22.219181060791 |
155 | | RAW | sha3-384 | 48 | 22.259950637817 |
156 | | RAW | haval256,4 | 32 | 24.071931838989 |
157 | | HEX | haval256,4 | 64 | 24.100065231323 |
158 | | RAW | haval224,4 | 28 | 24.12486076355 |
159 | | HEX | haval224,4 | 56 | 24.132966995239 |
160 | | RAW | haval192,4 | 24 | 24.198055267334 |
161 | | HEX | haval160,4 | 40 | 24.597883224487 |
162 | | HEX | haval192,4 | 48 | 24.653911590576 |
163 | | RAW | haval160,4 | 20 | 24.665832519531 |
164 | | HEX | haval128,4 | 32 | 24.919033050537 |
165 | | RAW | haval128,4 | 16 | 25.200128555298 |
166 | | RAW | sha224 | 28 | 25.952100753784 |
167 | | RAW | sha256 | 32 | 25.97713470459 |
168 | | HEX | sha224 | 56 | 26.051044464111 |
169 | | HEX | sha256 | 64 | 26.114940643311 |
170 | | HEX | ripemd320 | 80 | 28.150081634521 |
171 | | HEX | ripemd160 | 40 | 28.232097625732 |
172 | | RAW | ripemd160 | 20 | 28.304100036621 |
173 | | RAW | ripemd320 | 40 | 28.388977050781 |
174 | | HEX | haval224,5 | 56 | 29.100894927979 |
175 | | RAW | haval256,5 | 32 | 29.104948043823 |
176 | | HEX | haval160,5 | 40 | 29.134035110474 |
177 | | HEX | haval256,5 | 64 | 29.13498878479 |
178 | | RAW | haval224,5 | 28 | 29.138088226318 |
179 | | RAW | haval160,5 | 20 | 29.186964035034 |
180 | | RAW | haval192,5 | 24 | 29.205083847046 |
181 | | RAW | haval128,5 | 16 | 29.221057891846 |
182 | | HEX | haval128,5 | 32 | 29.263973236084 |
183 | | HEX | haval192,5 | 48 | 29.27303314209 |
184 | | HEX | sha3-512 | 128 | 32.00101852417 |
185 | | RAW | sha3-512 | 64 | 32.001972198486 |
186 | | RAW | whirlpool | 64 | 50.601005554199 |
187 | | HEX | whirlpool | 128 | 50.703048706055 |
188 | | HEX | gost | 64 | 95.890998840332 |
189 | | RAW | gost | 32 | 95.905780792236 |
190 | | RAW | gost-crypto | 32 | 95.912933349609 |
191 | | HEX | gost-crypto | 64 | 95.93391418457 |
192 | | HEX | snefru | 64 | 195.09100914001 |
193 | | HEX | snefru256 | 64 | 195.57094573975 |
194 | | RAW | snefru256 | 32 | 195.965051651 |
195 | | RAW | snefru | 32 | 197.18909263611 |
196 | | RAW | md2 | 16 | 830.39283752441 |
197 | | HEX | md2 | 32 | 838.06991577148 |
198 |
199 |
200 |
201 | ## JSON vs Serialize
202 |
203 | It benchmark to serialize and de-serialize variables
204 |
205 | [json_vs_serialize.php](json_vs_serialize.php)
206 |
207 | array
208 |
209 | ```php
210 | $data=['field1'=>"hello",'field2'=>450,'field3'=>['field4'=>'hello','field5'=>450]];
211 | ```
212 |
213 | object StdClass
214 |
215 | ```php
216 | $data=new stdClass();
217 | $data->field1="hello";
218 | $data->field2=450;
219 | $data->field3=new stdClass();
220 | $data->field3->field4="hello";
221 | $data->field3->field5=450;
222 | ```
223 |
224 | object (defined by a class)
225 |
226 | ```php
227 | $data=new MyClass();
228 | $data->field1="hello";
229 | $data->field2=450;
230 | $data->field3=new MyClass2();
231 | $data->field3->field4="hello";
232 | $data->field3->field5=450;
233 | ```
234 |
235 |
236 |
237 | ### Result (less is better)
238 |
239 | | type | time |
240 | | :-------------------------- | :--------------------------- |
241 | | json_encode array | 23.508071899414 |
242 | | serialize array | **20.003318786621** (better) |
243 | | json_decode array | 120.9020614624 |
244 | | unserialize array | 39.196014404297 |
245 | | json_encode object stdclass | 24.199485778809 |
246 | | serialize object stdclass | 32.901763916016 |
247 | | json_decode object stdclass | 127.10094451904 |
248 | | unserialize object stdclass | 102.61535644531 |
249 | | json_encode object | 24.39022064209 |
250 | | serialize object | 32.877922058105 |
251 | | json_decode object | 126.21879577637 |
252 | | unserialize object | **129.1036605835** (worst) |
253 |
254 |
255 |
256 | ## DEFINE / CONST / ENV
257 |
258 | We test the performance between to read an environment variable or to use a constant.
259 |
260 |
261 |
262 | ### Result (less is better)
263 |
264 | | DEFINE CONST | CONST | getEnv() | function |
265 | | :------------------ | :------------------ | :---------------- | ------------------- |
266 | | 0.00066995620727539 | 0.00067687034606934 | 0.056761026382446 | 0.00053286552429199 |
267 |
268 | Conclusion, **define()** and **const** have practically the same performance (at least in PHP 7.4), while **getEnv()** is considerably bad. However,getEnv() is acceptable even when it is 10000% slower (50000 getEnv() took 50ms.).
269 |
270 | We also tested to call a function and it is way fast than getEnv()
271 |
272 | > Conclusion: getEnv() is not cached neither it is loaded into PHP. Instead, it is calculated each time when it is called.
273 |
274 |
275 |
276 | ## array_map vs foreach
277 |
278 | [benchmark_arraymap_foreach.php](benchmark_arraymap_foreach.php)
279 |
280 | It tests the performance between **foreach** and **array_map**
281 |
282 | ### Result 7.x (less is better)
283 |
284 | | foreach | array_map | array_map (static) | array_map (calling a function) |
285 | | :---------------------------- | :--------------- | :----------------- | :----------------------------- |
286 | | **0.10213899612427** (better) | 0.18259811401367 | 0.18230390548706 | 0.17731499671936 |
287 |
288 | ### Result 8.x (less is better)
289 |
290 | | foreach | array_map | array_map (static) | array_map (calling a function) |
291 | | :--------------------------- | :------------------ | :------------------ | :----------------------------- |
292 | | 0.12356901168823242 (better) | 0.19595623016357422 | 0.19472408294677734 | 0.19141697883605957 |
293 |
294 |
295 | Conclusion: Foreach is still faster. Between array_map and array_map (static), there is not a big difference. And using array_map with a function is slightly fast.
296 |
297 | ## isset vs @ at
298 |
299 | [benchmark_isset_vs_at.php](benchmark_isset_vs_at.php)
300 |
301 | This test could be a bit misleading but the goal is to benchmark the speed even when both ways returns different values.
302 |
303 | ```php
304 | $r=isset($var); // isset (it returns true if the variable exists)
305 | $r=@$var // at
306 | $r= $var ?? null; // nullcol php >7.0
307 | $r= @$var ? $exist : null; // ternary
308 | $r=isset($var) ?? $var; // issetnull7 php>7.0
309 | $r=isset($var) ? $var : null; // issetnull5 php>7.0
310 | !isset($var) and $var=null; // hacky but it works (however it doesn't assigns value if the value does not exists)
311 | ```
312 |
313 | ### Result (smaller is better)
314 |
315 | | isset | at | nullcol | ternary | issetnull7 | issetnull5 | hacky |
316 | | :------------------ | :----------------- | :----------------- | :------------------ | :------------------- | :------------------ | :------------------- |
317 | | 0.01783585548400879 | 0.3733489513397217 | 0.0551450252532959 | 0.38265109062194824 | 0.024428129196166992 | 0.02412700653076172 | 0.014414072036743164 |
318 |
319 | Smaller is better.
320 |
321 | Conclusion: @ is between 1 and 2 order of magnitude slower.
322 |
323 | ## Type hinting
324 |
325 | How type hinting affects the performance?
326 |
327 | [benchmark_types_arguments.php](benchmark_types_arguments.php)
328 |
329 | Let's say the next code
330 |
331 | ```php
332 | /**
333 | * @param DummyClass $arg1
334 | * @param DummyClass $arg2
335 | *
336 | * @return DummyClass
337 | */
338 | function php5($arg1,$arg2){
339 | return new DummyClass();
340 | }
341 | function php7(DummyClass $arg1,DummyClass $arg2): DummyClass {
342 | return new DummyClass();
343 | }
344 | ```
345 |
346 | ### Result (smaller is better)
347 |
348 | | php5 | php7 |
349 | | :-------------------- | :-------------------- |
350 | | 0.0006339550018310547 | 0.0007991790771484375 |
351 |
352 | Smaller is better.
353 |
354 | **Conclusion**: In general, type hinting is around 10% slower but both methods are enough fast to made any difference.
355 |
356 | While it could be useful but if you are using a proper IDE, then you could rely on PHPDoc, it's verbose but it is more complete and without affecting the performance.
357 |
358 |
359 | ## Benchmark eval
360 |
361 | [benchmark_eval.php](benchmark_eval.php)
362 |
363 | ```php
364 | $r=ping("pong"); // no eval
365 | eval('$r=ping("pong");'); // eval
366 | $r=eval('return ping("pong");'); // eval 2
367 |
368 | $fnname='ping';
369 | $r=$fnname("pong"); // dynamic_function (calling a function using a variable)
370 | ```
371 |
372 | ### Result (smaller is better)
373 |
374 | | no_eval | eval | eval2 | dynamic_function |
375 | | :------------------- | :------------------ | :-------------- | :------------------ |
376 | | 0.003139972686767578 | 0.14499497413635254 | 0.1302490234375 | 0.00487518310546875 |
377 |
378 | **Conclusion**: **Eval** is considerably slow and it should be avoided if possible
379 |
380 | ## Benchmark count vs is_array and count
381 |
382 | [benchmark_count_isarray](benchmark_count_isarray.php)
383 |
384 | ```php
385 | $r=@count($array1);
386 | $r=is_array($array1)? count($array1) : null;
387 | is_array($noarray) and $r=count($noarray);
388 | ```
389 |
390 | ### Result (smaller is better)
391 |
392 | | count | is_array count | is_array count 2 |
393 | | :------------------ | :------------------- | :--------------------------------- |
394 | | 0.05631399154663086 | 0.003616809844970703 | **0.0020818710327148438** (better) |
395 |
396 | **Conclusion**: @ is consistently bad in an order of magnitude. We could gain a bit of performance using a logic operator (it only assigns the value if the value is an array)
397 |
398 | > Note: @count($array) crashes in PHP 8 when $array is not an object
399 |
400 |
401 |
402 | ## Benchmark is_array vs is_countable
403 |
404 | [benchmark_is_array_countable.php](benchmark_is_array_countable.php)
405 |
406 | ```
407 | $r=is_countable($array1);
408 | $r=is_array($array1);
409 | $r=gettype($noarray);
410 | $r=get_debug_type($noarray);
411 | ```
412 |
413 | ### Result (smaller is better)
414 |
415 | | is_countable (PHP 7.x) | is_array count | gettype | get_debug_type (PHP 8) |
416 | | :--------------------- | :-------------------- | :------------------- | :--------------------- |
417 | | 0.0044329166412353516 | 0.0022399425506591797 | 0.002468109130859375 | 0.004589080810546875 |
418 |
419 | **Conclusion**: is_countable is surprisingly bad. Also, get_debug_type() is slower than gettype()
420 |
421 |
422 |
423 | ## Benchmark array_key_exists vs isset
424 |
425 | ```php
426 | $r=array_key_exists('repeated',$array1);
427 | $r=isset($array1['repeated']);
428 | ```
429 |
430 | [benchmark_array_key_exists_vs_isset.php]([benchmark_array_key_exists_vs_isset.php)
431 |
432 | Note: if the key exists **$array1['repeated']** but the value is null, then isset() returns false while array_key_exists
433 | returns true. So they are not exactly the same.
434 |
435 | ### Result (smaller is better)
436 |
437 | | array_key_exists | isset |
438 | | :------------------ | :-------------------- |
439 | | 0.00333404541015625 | 0.0028688907623291016 |
440 |
441 | **Conclusion**: isset() is the fastest by usually an 40-80%.
442 |
443 | ## Benchmark str_contains vs str_pos
444 |
445 | [benchmark_str_contains_vs_strpos.php](benchmark_str_contains_vs_strpos.php)
446 |
447 | ```php
448 | $r=str_contains($text,'mary');
449 | $r=strpos($text,'mary');
450 | ```
451 |
452 | ### Result (smaller is better)
453 |
454 | | str_contains | strpos |
455 | | :------------------ | :------------------ |
456 | | 0.09099698066711426 | 0.09030508995056152 |
457 |
458 | They give the same performance but conceptually (if you want to see if a string exists inside other) **str_contains** is better because it always returns a boolean while **strpos** returns an **int** or a **false**.
459 |
460 | ## Benchmark file_exists vs is_file
461 |
462 | [benchmark_file_exists_vs_is_file.php](benchmark_file_exists_vs_is_file.php)
463 |
464 | This benchmark measures the speed of both functions where the file exists and where the file does not exist.
465 |
466 | ### Result (smaller is better)
467 |
468 | Windows:
469 |
470 | | file_exists | is_file |
471 | | :---------------- | :----------------- |
472 | | 3.451578140258789 | 2.0834150314331055 |
473 |
474 | Linux:
475 |
476 | | file_exists | is_file |
477 | | :-------------- | :---------------- |
478 | | 0.1745491027832 | 0.062805891036987 |
479 |
480 | Conclusion: is_file() is faster in almost the double of speed and Linux is faster than Windows.
481 |
482 | ## Benchmark array_merge vs others
483 |
484 | [benchmark_array_merge_vs_plus.php](benchmark_array_merge_vs_plus.php)
485 |
486 | We compare array_merge() versus the rest. We should notice that they could return different results considering if we have duplicates or if the value stored is not indexed. So, they are not always interchangeable.
487 |
488 | ```php
489 | $r=array_merge($array1,$array2); // array merge
490 | $r=array_replace($array1,$array2); // array_replay
491 | $r= $array1 + $array2; // plus
492 | $r= foreachMerge($array1,$array2); // foreach concatenates the two values using a foreach loop
493 | ```
494 |
495 | ### Result (smaller is better)
496 |
497 | | array_merge | array_replace | plus | foreach |
498 | | :------------------------ | :----------------------- | :----------------------- | :---------------------- |
499 | | 0.015676021575927734 (12) | 0.019279003143310547 (9) | 0.014889001846313477 (9) | 0.05200004577636719 (9) |
500 |
501 | > note: the number between parenthesis indicates the number of elements returned.
502 | >
503 | > array_merge(['a'=>'1','b'=>'2',1,2],['a'=>'1','b'=>'2',1,2]) returns the values ['a'=>'1','b'=>'2',1,2,1,2]. **Array_replace**, **plus** and **foreach** does not duplicates the values without indexes.
504 |
505 | Conclusion: plus is better than array_replace and it does a similar job. array_merge generates an acceptable performance (even the arrays has duplicates). Also, you don't want to create your own merge using **foreach**.
506 |
507 | ## Benchmark array versus object
508 |
509 | This benchmark tests the next functionalities:
510 |
511 | * Create a variable.
512 | * Then, it reads a simple value
513 | * And it adds to the list (the list is created every round)
514 |
515 | ```php
516 | $array_numeric=[$hello,$second,$third];
517 |
518 | $array_not_numeric=['hello'=>$hello,'second'=>$second,'third'=>$third];
519 |
520 | $object_constructor=DummyClass('world',0,20.3);
521 |
522 | $object_no_constructor=new DummyClass2();
523 | $object_no_constructor->hello='world';
524 | $object_no_constructor->second=0;
525 | $object_no_constructor->third=20.3;
526 | ```
527 |
528 | What is a factory? A factory is a function used for creating an entity (in this case, an array).
529 |
530 | what is a constructor? A constructor is part of a class and is used to initialize the instance of the object.
531 |
532 | ### Result (smaller is better)
533 |
534 | It is the result of the benchmarks in seconds
535 |
536 | | array numeric no factory | array no factory | array numeric factory | array factory | object constructor | object no constructor | object no constructor setter/getter | object no constructor setter/getter (magic) | object no constructor stdClass |
537 | | :----------------------- | :------------------ | :-------------------- | :------------------ | :------------------ | :-------------------- | :---------------------------------- | :------------------------------------------ | :----------------------------- |
538 | | 0.038275957107543945 | 0.04024696350097656 | 0.12892484664916992 | 0.15126800537109375 | 0.12696218490600586 | 0.08770990371704102 | 0.21163702011108398 | 0.3990211486816406 | 0.13244986534118652 |
539 |
540 | ### Result in percentage compared with the smaller result.
541 |
542 | | array numeric no factory | array no factory | array numeric factory | array factory | object constructor | object no constructor | object no constructor setter/getter | object no constructor setter/getter (magic) | object no constructor stdClass |
543 | | :----------------------- | :--------------- | :-------------------- | :------------ | :----------------- | :-------------------- | :---------------------------------- | :------------------------------------------ | :----------------------------- |
544 | | 0% | 5.15% | 236.83% | 295.2% | 231.7% | 129.15% | 452.92% | 942.49% | 246.04% |
545 |
546 | Conclusion:
547 |
548 | * The difference between an array numeric and an associative array is a mere 5%, so you can say that they are the same.
549 | * The use of an object is +100% slower but it is still acceptable in most conditions (aka it uses the double of time).
550 | * The call to a method or the use of a constructor increases the value considerably. **Also, it's better to use an object/constructor than an array/factory.** Why? I don't know.
551 | * The use of setter/getters impacts the performance considerably. If you can then you should avoid that.
552 | * The use of magic setters and getters is horrible (almost 10 times slower). Is it the reason why Laravel is slow?
553 | * Also, the setters and getters are vanilla, they don't validate if the field exists of any other validation.
554 | * And the use of a **stdClass** (anonymous class) is also bad but not as bad as to use setter and getters.
555 |
556 | ps: The test ran 1 million times and the difference is smaller than 0.3 seconds, so is it important?
557 |
558 | Let's say we have 100 concurrent users (not a small number but not impossible), and we are processing and returning a list with 1000 values. It is 100x1000 = 100'000 objects. So, if we consider 100'000 objects, then the difference is less than 0.03 seconds in the worst case. However, our systems process more than a single operation, so if we are showing a list of objects, then we also validating, showing other values, validating, reading from the database and storing into the memory and returning to the customer via a web or serialized, so this value could considerable and the use of the CPU is on-top of other processes. It is not a big deal for a small project, but it is important for a big project.
559 |
560 | tl/dr
561 |
562 | ```php
563 | $customer[0]='john'; // faster but it is hard to understand
564 | $customer['name']='john'; // almost as fast as the first one but it is clear to understand (it also uses more memory)
565 | $customer->name='john'; // (where $customer is an object of the class Customer) slower but it still acceptable.
566 | $customer->name='john'; // (where $customer is an object of the class stdClass) the double of slower than to use a class.
567 | $customer=new Customer('john'); // (constructor) even slower but is still acceptable;
568 | $customer=factory('john'); // (where factory is an array that returns an array). Slower than the use of constructor.
569 | $customer->setName('john'); // bad performance
570 | $customer->name='john'; // (where the class uses a magic method) awful performance, avoid this one.
571 | ```
572 |
573 | https://github.com/EFTEC/php-benchmarks/blob/master/benchmark_array_vs_object.php
574 |
575 | ## Echo vs Concat vs Implode
576 |
577 | Which is faster for multiples concatenation?
578 |
579 | | echo | concat | implode |
580 | | :------------------ | :------------------ | :------------------ |
581 | | 0.00058293342590332 | 0.00057601928710938 | 0.00058507919311523 |
582 |
583 | In conclusion, all of them are pretty similar.
584 |
585 |
586 |
587 | https://github.com/EFTEC/php-benchmarks/blob/master/benchmark_echo_vs_strings.php
588 |
589 | ## Constant vs variable vs literal
590 |
591 | We compare the use of a constant versus a variable and a literal. All of them stores a string.
592 |
593 | The literal is defined for each cycle.
594 |
595 | ```php
596 | const HELLO = 'HELLO WORLD';
597 | $variable = 'HELL WORLD';
598 | 'HELLO WORLD'
599 | ```
600 |
601 |
602 |
603 | | constant | variable | literal |
604 | | :---------------- | :---------------- | :---------------- |
605 | | 0.047255992889404 | 0.041103839874268 | 0.041267156600952 |
606 | | 0.047415971755981 | 0.040828943252563 | 0.041354894638062 |
607 | | 0.047232151031494 | 0.041209936141968 | 0.041146993637085 |
608 | | 0.047588109970093 | 0.040886878967285 | 0.041790962219238 |
609 | | 0.047214031219482 | 0.041198968887329 | 0.042134046554565 |
610 | | 0.04762601852417 | 0.041079998016357 | 0.041344881057739 |
611 | | 0.047240018844604 | 0.04153299331665 | 0.041368007659912 |
612 | | 0.04719614982605 | 0.042517900466919 | 0.041674137115479 |
613 | | 0.072301149368286 | 0.070401906967163 | 0.050674915313721 |
614 | | 0.049120903015137 | 0.041906118392944 | 0.041185140609741 |
615 |
616 | Conclusion: the constant is a bit slow in practically every case. The use of a variable or a literal is the same, even when the literal is apparently created many times.
617 |
618 | ## Serializations
619 |
620 | https://github.com/EFTEC/php-benchmarks/blob/master/benchmark_serialization.php
621 |
622 | We benchmark the serialization using different methods.
623 |
624 | * serialize (PHP serialization function)
625 | * igbinary (pecl)
626 | * json
627 | * msgpack (pecl)
628 |
629 | It is the data that was serialized
630 |
631 | ```php
632 | $input = array();
633 | for ($i = 0; $i < 1000; $i++) {
634 | $input["k-$i"] = [$i];
635 | $input["k-$i"]['k1'] =['a','b','c'];
636 | $input["k-$i"]['k1']['k2'] =['a','b',10,20,30,true];
637 | }
638 | ```
639 |
640 | It is complex but not really complex. It's not a huge array, just 1000 arrays with multiples dimensions (the equivalent to show a table with 1000 data and some relations)
641 |
642 |
643 |
644 | ### Serialize: (in seconds less is better)
645 |
646 | | serialize | igbinary_serialize | json_encode | packer->pack (msgpack) |
647 | | :------------------- | :----------------- | :------------------- | :--------------------- |
648 | | 0.3174231052 154.67% | 0.2052299976 100% | 0.2650880814 129.17% | 0.2757101059 134.34% |
649 |
650 | Conclusion: **igbinary** is a bit faster to serialize but the different is not as big.
651 |
652 | ### De-serialize: (in seconds less is better)
653 |
654 | | unserialize | igbinary_unserialize | json_decode | packer->unpack (msgpack) |
655 | | :------------------- | :------------------- | :--------------- | :----------------------- |
656 | | 0.6460649967 228.28% | 0.2830090523 100% | 1.816905975 642% | 0.6301090717 222.65% |
657 |
658 | Conclusion: **igbinary** is a bit faster to unserialize
659 |
660 | ### Size: (in bytes less is better)
661 |
662 | | serialize | igbinary_serialize | json_encode | packer->pack (msgpack) |
663 | | :------------- | :----------------- | :------------ | :--------------------- |
664 | | 144789 430.05% | 33668 100% | 72781 216.17% | 34509 102.5% |
665 |
666 | **Conclusion: igbinary hands down (at least in my test machine)**
667 |
668 | Iwill try it again but with a different input value (without nested values)
669 |
670 | ```php
671 | $input = array();
672 | for ($i = 0; $i < 1000; $i++) {
673 | $input["k-$i"] = ["k-$i"];
674 | }
675 | ```
676 |
677 |
678 |
679 | ### Serialize: (in seconds less is better)
680 |
681 | | serialize | igbinary_serialize | json_encode | packer->pack (msgpack) |
682 | | :------------------- | :------------------- | :------------------- | :--------------------- |
683 | | 0.05781698227 102.6% | 0.1744749546 309.63% | 0.05888605118 104.5% | 0.05634999275 100% |
684 |
685 | ### De-serialize: (in seconds less is better)
686 |
687 | | unserialize | igbinary_unserialize | json_decode | packer->unpack (msgpack) |
688 | | :------------------ | :------------------- | :------------------- | :----------------------- |
689 | | 0.1529650688 165.5% | 0.09242415428 100% | 0.2922010422 316.15% | 0.1266789436 137.06% |
690 |
691 | ### Size: (in bytes less is better)
692 |
693 | | serialize | igbinary_serialize | json_encode | packer->pack (msgpack) |
694 | | :------------ | :----------------- | :----------- | :--------------------- |
695 | | 33789 264.33% | 13641 106.71% | 17781 139.1% | 12783 100% |
696 |
697 | ### Input is equals to output: (no means error)
698 |
699 | | unserialize | igbinary_unserialize | json_decode | packer->pack (msgpack) |
700 | | :---------- | :------------------- | :---------- | :--------------------- |
701 | | yes | yes | yes | yes |
702 |
703 | **Conclusion: msgpacker is faster serializing and in size, while igbinary is faster unserializing.**
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
--------------------------------------------------------------------------------