3v4l.org

run code in 500+ PHP versions simultaneously
<?php declare(strict_types=1); /* |-------------------------------------------------------------------------- | Benchmark: | | 1. Dynamic call: | $instance->$method(...$args) | | 2. Reflection: | ReflectionMethod::invoke() | | 3. Cached first-class callable: | self::method(...) | | 4. Cached closure + Closure::call() | | This benchmark is specifically useful for: | - AOP | - proxy dispatch | - interceptor systems | - generated wrappers | |-------------------------------------------------------------------------- */ final class Bench { private int $value = 42; public function targetMethod(int $a, int $b): int { return $this->value + $a + $b; } public function run(int $iterations = 5_000_000): void { $method = 'targetMethod'; $args = [10, 20]; echo "Iterations: {$iterations}\n"; echo "Object ID : " . spl_object_id($this) . "\n"; echo str_repeat('-', 70) . "\n"; /* * Warmup (important for fair benchmark) */ for ($i = 0; $i < 10000; $i++) { $this->targetMethod(1, 2); } /* * Reflection prepared once */ $reflection = new ReflectionMethod(self::class, 'targetMethod'); /* * First-class callable prepared once * * You can test BOTH variants: * * Variant A: * $cachedClosure = $this->targetMethod(...); * * Variant B: * $cachedClosure = self::targetMethod(...); * * (both valid inside object context) */ $cachedClosure = self::targetMethod(...); /* * Another object for Closure::call() */ $another = new self(); /* * Prevent optimizer from eliminating calls */ $checksum = 0; /* |-------------------------------------------------------------------------- | 1. Dynamic method call |-------------------------------------------------------------------------- */ $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $checksum += $this->$method(...$args); } $dynamicTime = hrtime(true) - $start; /* |-------------------------------------------------------------------------- | 2. ReflectionMethod::invoke() |-------------------------------------------------------------------------- */ $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $checksum += $reflection->invoke($this, ...$args); } $reflectionTime = hrtime(true) - $start; /* |-------------------------------------------------------------------------- | 3. Cached closure direct call |-------------------------------------------------------------------------- */ $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $checksum += $cachedClosure(...$args); } $closureTime = hrtime(true) - $start; /* |-------------------------------------------------------------------------- | 4. Cached closure + Closure::call() |-------------------------------------------------------------------------- */ $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $checksum += $cachedClosure->call($another, ...$args); } $callTime = hrtime(true) - $start; echo "Checksum (ignore): {$checksum}\n"; echo str_repeat('-', 70) . "\n"; $this->printResult('1. Dynamic $obj->$method()', $dynamicTime, $iterations); $this->printResult('2. ReflectionMethod::invoke()', $reflectionTime, $iterations); $this->printResult('3. Cached closure direct', $closureTime, $iterations); $this->printResult('4. Closure->call()', $callTime, $iterations); echo str_repeat('-', 70) . "\n"; echo "Lower is better\n"; } private function printResult( string $label, int $nanoseconds, int $iterations ): void { $ms = $nanoseconds / 1_000_000; $nsPerOp = $nanoseconds / $iterations; printf( "%-35s %12.3f ms (%8.2f ns/op)\n", $label, $ms, $nsPerOp ); } } (new Bench())->run();
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/DYj84
function name:  (null)
number of ops:  5
compiled vars:  none
line      #* E I O op                               fetch          ext  return  operands
-----------------------------------------------------------------------------------------
  169     0  E >   NEW                                                  $0      'Bench'
          1        DO_FCALL                                          0          
          2        INIT_METHOD_CALL                                             $0, 'run'
          3        DO_FCALL                                          0          
          4      > RETURN                                                       1

Class Bench:
Function targetmethod:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/DYj84
function name:  targetMethod
number of ops:  9
compiled vars:  !0 = $a, !1 = $b
line      #* E I O op                               fetch          ext  return  operands
-----------------------------------------------------------------------------------------
   33     0  E >   RECV                                                 !0      
          1        RECV                                                 !1      
   35     2        FETCH_OBJ_R                                          ~2      'value'
          3        ADD                                                  ~3      ~2, !0
          4        ADD                                                  ~4      ~3, !1
          5        VERIFY_RETURN_TYPE                                           ~4
          6      > RETURN                                                       ~4
   36     7*       VERIFY_RETURN_TYPE                                           
          8*     > RETURN                                                       null

End of function targetmethod

Function run:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 42) Position 1 = 27
Branch analysis from position: 27
2 jumps found. (Code = 44) Position 1 = 29, Position 2 = 22
Branch analysis from position: 29
1 jumps found. (Code = 42) Position 1 = 53
Branch analysis from position: 53
2 jumps found. (Code = 44) Position 1 = 55, Position 2 = 47
Branch analysis from position: 55
1 jumps found. (Code = 42) Position 1 = 74
Branch analysis from position: 74
2 jumps found. (Code = 44) Position 1 = 76, Position 2 = 66
Branch analysis from position: 76
1 jumps found. (Code = 42) Position 1 = 93
Branch analysis from position: 93
2 jumps found. (Code = 44) Position 1 = 95, Position 2 = 87
Branch analysis from position: 95
1 jumps found. (Code = 42) Position 1 = 113
Branch analysis from position: 113
2 jumps found. (Code = 44) Position 1 = 115, Position 2 = 106
Branch analysis from position: 115
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 106
2 jumps found. (Code = 44) Position 1 = 115, Position 2 = 106
Branch analysis from position: 115
Branch analysis from position: 106
Branch analysis from position: 87
2 jumps found. (Code = 44) Position 1 = 95, Position 2 = 87
Branch analysis from position: 95
Branch analysis from position: 87
Branch analysis from position: 66
2 jumps found. (Code = 44) Position 1 = 76, Position 2 = 66
Branch analysis from position: 76
Branch analysis from position: 66
Branch analysis from position: 47
2 jumps found. (Code = 44) Position 1 = 55, Position 2 = 47
Branch analysis from position: 55
Branch analysis from position: 47
Branch analysis from position: 22
2 jumps found. (Code = 44) Position 1 = 29, Position 2 = 22
Branch analysis from position: 29
Branch analysis from position: 22
filename:       /in/DYj84
function name:  run
number of ops:  158
compiled vars:  !0 = $iterations, !1 = $method, !2 = $args, !3 = $i, !4 = $reflection, !5 = $cachedClosure, !6 = $another, !7 = $checksum, !8 = $start, !9 = $dynamicTime, !10 = $reflectionTime, !11 = $closureTime, !12 = $callTime
line      #* E I O op                               fetch          ext  return  operands
-----------------------------------------------------------------------------------------
   38     0  E >   RECV_INIT                                            !0      5000000
   40     1        ASSIGN                                                       !1, 'targetMethod'
   41     2        ASSIGN                                                       !2, <array>
   43     3        ROPE_INIT                                         3  ~16     'Iterations%3A+'
          4        ROPE_ADD                                          1  ~16     ~16, !0
          5        ROPE_END                                          2  ~15     ~16, '%0A'
          6        ECHO                                                         ~15
   44     7        INIT_FCALL                                                   'spl_object_id'
          8        FETCH_THIS                                           ~18     
          9        SEND_VAL                                                     ~18
         10        DO_ICALL                                             $19     
         11        CONCAT                                               ~20     'Object+ID+%3A+', $19
         12        CONCAT                                               ~21     ~20, '%0A'
         13        ECHO                                                         ~21
   45    14        INIT_FCALL                                                   'str_repeat'
         15        SEND_VAL                                                     '-'
         16        SEND_VAL                                                     70
         17        DO_ICALL                                             $22     
         18        CONCAT                                               ~23     $22, '%0A'
         19        ECHO                                                         ~23
   50    20        ASSIGN                                                       !3, 0
         21      > JMP                                                          ->27
   51    22    >   INIT_METHOD_CALL                                             'targetMethod'
         23        SEND_VAL_EX                                                  1
         24        SEND_VAL_EX                                                  2
         25        DO_FCALL                                          0          
   50    26        PRE_INC                                                      !3
         27    >   IS_SMALLER                                                   !3, 10000
         28      > JMPNZ                                                        ~27, ->22
   57    29    >   NEW                                                  $28     'ReflectionMethod'
         30        SEND_VAL_EX                                                  'Bench'
         31        SEND_VAL_EX                                                  'targetMethod'
         32        DO_FCALL                                          0          
         33        ASSIGN                                                       !4, $28
   72    34        INIT_STATIC_METHOD_CALL                                      'targetMethod'
         35        CALLABLE_CONVERT                                     ~31     
         36        ASSIGN                                                       !5, ~31
   77    37        NEW                              self                $33     
         38        DO_FCALL                                          0          
         39        ASSIGN                                                       !6, $33
   82    40        ASSIGN                                                       !7, 0
   90    41        INIT_FCALL                                                   'hrtime'
         42        SEND_VAL                                                     <true>
         43        DO_ICALL                                             $37     
         44        ASSIGN                                                       !8, $37
   92    45        ASSIGN                                                       !3, 0
         46      > JMP                                                          ->53
   93    47    >   INIT_METHOD_CALL                                             !1
         48        SEND_UNPACK                                                  !2
         49        CHECK_UNDEF_ARGS                                             
         50        DO_FCALL                                          1  $40     
         51        ASSIGN_OP                                         1          !7, $40
   92    52        PRE_INC                                                      !3
         53    >   IS_SMALLER                                                   !3, !0
         54      > JMPNZ                                                        ~43, ->47
   96    55    >   INIT_FCALL                                                   'hrtime'
         56        SEND_VAL                                                     <true>
         57        DO_ICALL                                             $44     
         58        SUB                                                  ~45     $44, !8
         59        ASSIGN                                                       !9, ~45
  104    60        INIT_FCALL                                                   'hrtime'
         61        SEND_VAL                                                     <true>
         62        DO_ICALL                                             $47     
         63        ASSIGN                                                       !8, $47
  106    64        ASSIGN                                                       !3, 0
         65      > JMP                                                          ->74
  107    66    >   INIT_METHOD_CALL                                             !4, 'invoke'
         67        FETCH_THIS                                           $50     
         68        SEND_VAR_EX                                                  $50
         69        SEND_UNPACK                                                  !2
         70        CHECK_UNDEF_ARGS                                             
         71        DO_FCALL                                          1  $51     
         72        ASSIGN_OP                                         1          !7, $51
  106    73        PRE_INC                                                      !3
         74    >   IS_SMALLER                                                   !3, !0
         75      > JMPNZ                                                        ~54, ->66
  110    76    >   INIT_FCALL                                                   'hrtime'
         77        SEND_VAL                                                     <true>
         78        DO_ICALL                                             $55     
         79        SUB                                                  ~56     $55, !8
         80        ASSIGN                                                       !10, ~56
  118    81        INIT_FCALL                                                   'hrtime'
         82        SEND_VAL                                                     <true>
         83        DO_ICALL                                             $58     
         84        ASSIGN                                                       !8, $58
  120    85        ASSIGN                                                       !3, 0
         86      > JMP                                                          ->93
  121    87    >   INIT_DYNAMIC_CALL                                            !5
         88        SEND_UNPACK                                                  !2
         89        CHECK_UNDEF_ARGS                                             
         90        DO_FCALL                                          1  $61     
         91        ASSIGN_OP                                         1          !7, $61
  120    92        PRE_INC                                                      !3
         93    >   IS_SMALLER                                                   !3, !0
         94      > JMPNZ                                                        ~64, ->87
  124    95    >   INIT_FCALL                                                   'hrtime'
         96        SEND_VAL                                                     <true>
         97        DO_ICALL                                             $65     
         98        SUB                                                  ~66     $65, !8
         99        ASSIGN                                                       !11, ~66
  132   100        INIT_FCALL                                                   'hrtime'
        101        SEND_VAL                                                     <true>
        102        DO_ICALL                                             $68     
        103        ASSIGN                                                       !8, $68
  134   104        ASSIGN                                                       !3, 0
        105      > JMP                                                          ->113
  135   106    >   INIT_METHOD_CALL                                             !5, 'call'
        107        SEND_VAR_EX                                                  !6
        108        SEND_UNPACK                                                  !2
        109        CHECK_UNDEF_ARGS                                             
        110        DO_FCALL                                          1  $71     
        111        ASSIGN_OP                                         1          !7, $71
  134   112        PRE_INC                                                      !3
        113    >   IS_SMALLER                                                   !3, !0
        114      > JMPNZ                                                        ~74, ->106
  138   115    >   INIT_FCALL                                                   'hrtime'
        116        SEND_VAL                                                     <true>
        117        DO_ICALL                                             $75     
        118        SUB                                                  ~76     $75, !8
        119        ASSIGN                                                       !12, ~76
  140   120        ROPE_INIT                                         3  ~79     'Checksum+%28ignore%29%3A+'
        121        ROPE_ADD                                          1  ~79     ~79, !7
        122        ROPE_END                                          2  ~78     ~79, '%0A'
        123        ECHO                                                         ~78
  141   124        INIT_FCALL                                                   'str_repeat'
        125        SEND_VAL                                                     '-'
        126        SEND_VAL                                                     70
        127        DO_ICALL                                             $81     
        128        CONCAT                                               ~82     $81, '%0A'
        129        ECHO                                                         ~82
  143   130        INIT_METHOD_CALL                                             'printResult'
        131        SEND_VAL_EX                                                  '1.+Dynamic+%24obj-%3E%24method%28%29'
        132        SEND_VAR_EX                                                  !9
        133        SEND_VAR_EX                                                  !0
        134        DO_FCALL                                          0          
  144   135        INIT_METHOD_CALL                                             'printResult'
        136        SEND_VAL_EX                                                  '2.+ReflectionMethod%3A%3Ainvoke%28%29'
        137        SEND_VAR_EX                                                  !10
        138        SEND_VAR_EX                                                  !0
        139        DO_FCALL                                          0          
  145   140        INIT_METHOD_CALL                                             'printResult'
        141        SEND_VAL_EX                                                  '3.+Cached+closure+direct'
        142        SEND_VAR_EX                                                  !11
        143        SEND_VAR_EX                                                  !0
        144        DO_FCALL                                          0          
  146   145        INIT_METHOD_CALL                                             'printResult'
        146        SEND_VAL_EX                                                  '4.+Closure-%3Ecall%28%29'
        147        SEND_VAR_EX                                                  !12
        148        SEND_VAR_EX                                                  !0
        149        DO_FCALL                                          0          
  148   150        INIT_FCALL                                                   'str_repeat'
        151        SEND_VAL                                                     '-'
        152        SEND_VAL                                                     70
        153        DO_ICALL                                             $87     
        154        CONCAT                                               ~88     $87, '%0A'
        155        ECHO                                                         ~88
  149   156        ECHO                                                         'Lower+is+better%0A'
  150   157      > RETURN                                                       null

End of function run

Function printresult:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/DYj84
function name:  printResult
number of ops:  14
compiled vars:  !0 = $label, !1 = $nanoseconds, !2 = $iterations, !3 = $ms, !4 = $nsPerOp
line      #* E I O op                               fetch          ext  return  operands
-----------------------------------------------------------------------------------------
  153     0  E >   RECV                                                 !0      
  154     1        RECV                                                 !1      
  155     2        RECV                                                 !2      
  157     3        DIV                                                  ~5      !1, 1000000
          4        ASSIGN                                                       !3, ~5
  158     5        DIV                                                  ~7      !1, !2
          6        ASSIGN                                                       !4, ~7
  160     7        INIT_FCALL                                                   'printf'
  161     8        SEND_VAL                                                     '%25-35s+%2512.3f+ms+++%28%258.2f+ns%2Fop%29%0A'
  162     9        SEND_VAR                                                     !0
  163    10        SEND_VAR                                                     !3
  164    11        SEND_VAR                                                     !4
  160    12        DO_ICALL                                                     
  166    13      > RETURN                                                       null

End of function printresult

End of class Bench.

Generated using Vulcan Logic Dumper, using php 8.5.0


preferences:
169.03 ms | 1366 KiB | 17 Q