3v4l.org

run code in 300+ PHP versions simultaneously
<?php # Part 1: Prepare the classes. There should me lots of more code to make it robust, but I'm trying the PoC simple. class Repository { public array $data; /** * Works out the namespaced key and stores the value twice. * * If we're storing objects, they're stored as a reference anyway, so it doesn't matter that the same thing is there twice. * * If we store a scalar, then yes, we take up 2x the memory, but I think it's not a common use case and it's not a big deal. */ public function setReference(string $key, mixed $identity): void { // Stores the last $identity set with $key. If you don't re-use keys, this always keeps your object. Previous behaviour. $this->data[$key] = $identity; // Stores the namespaced identity. If you re-use keys and use the type as discriminator, this is what you'll be getting things back from. if (is_object($identity)) { $nsKey = $key.$this->getRealClass($identity::class); } else { $nsKey = $key.(get_debug_type($identity) ?? ''); } $this->data[$nsKey] = $identity; } /** * The @template notation below tells static analysers what value is returned when $type is provided. I tested this with PHPStorm - $boss = $repository->getReference('foo', Boss::class) correctly identifies $boss as Boss::class object. * * @template T * @param string $key * @param class-string<T> $type Could be a class name, or even a 'string' or 'int' value. * @return T */ public function getReference(string $key, string $type = null) { // If the $key doesn't exist, it doesn't matter what $type we might be asking for: the $key was never used when setting a value if (!array_key_exists($key, $this->data)) { throw new \Exception('Fixture not found'); } // No $type provided or not found using the namespaced key if (!$type) { return $this->data[$key]; } // The correct $key and $type combination exist - all good! if (array_key_exuists($key.$type, $this->data)) { // I'd assert the type here too, but for sake of example simplicity of this PoC, let's just not return $this->data[$key.$type]; } // If we made it here, the $key was used to set a value, but the $key we are asking for is not what the object was determined to be when it was being set. // The not-namespaced key happens to be of the correct type - this covers storing the Employee::class and asking for Person::class if (class_exists($type) && $this->data[$key] instanceof $type) { return $this->data[$key]; } // This means the last object stored using $key was not of $type. Since we're clearly saying we want a $type, we can't return anything throw new \Exception(sprintf( 'Fixture %s was found, but is type %s, not %s. Please ask for the correct type.', $key, get_debug_type($this->data[$key]), $type, )); } protected function getRealClass($className) { if (substr($className, -5) === 'Proxy') { return substr($className, 0, -5); } return $className; } } abstract class Person { public function __construct(public string $name) {} } class Boss extends Person {} class Employee extends Person {} # Part 2: Basic use case PoC $repository = new Repository(); $bossJohn = new Boss('John'); $bossJane = new Boss('Jane'); $employeeJim = new Employee('Jim'); $repository->setReference('boss', $bossJohn); $repository->setReference('boss', $bossJane); // overwrites 'boss' key with Jane because John and Jane are the same class assert($repository->getReference('boss', Boss::class) === $bossJane); // Retrieves last set boss that overwrites previous bosses assert($repository->getReference('boss') === $bossJane); // retrieves the non-namespaced value $repository->setReference('person', $bossJohn); $repository->setReference('person', $employeeJim); // adds Jim under duplicate 'person' key because of different classes assert($repository->getReference('person', Boss::class) === $bossJohn); // retrieves the correct person assert($repository->getReference('person', Employee::class) === $employeeJim); // retrieves the correct person assert($repository->getReference('person') === $employeeJim); # Part 3: PoC of things that I don't think are possible if https://github.com/doctrine/data-fixtures/pull/409 gets merged as is on 8th Feb 2023: // This is where things get intereesting, you can store other things than objects, if you want. Think of testing encryption keys generated on the fly etc. $repository->setReference('number', 31337); assert($repository->getReference('number') === 31337); $repository->setReference('number', 31337.0); assert($repository->getReference('number', 'float') === 31337.0); // Using this method we can use any parent in the inheritance structure assert($repository->getReference('person', Person::class) === $employeeJim); // Returns the last set 'person' even thought we're using a parent Person::class, not Employee::class // Using this method we can use any parent in the inheritance structure assert($repository->getReference('person', Boss::class) === $bossJohn); // Returns the correct fixture that duplicates keys, as long as we know what is the exact class we're after echo 'Success.';
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/HuZD6
function name:  (null)
number of ops:  128
compiled vars:  !0 = $repository, !1 = $bossJohn, !2 = $bossJane, !3 = $employeeJim
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   96     0  E >   NEW                                              $4      'Repository'
          1        DO_FCALL                                      0          
          2        ASSIGN                                                   !0, $4
   98     3        NEW                                              $7      'Boss'
          4        SEND_VAL_EX                                              'John'
          5        DO_FCALL                                      0          
          6        ASSIGN                                                   !1, $7
   99     7        NEW                                              $10     'Boss'
          8        SEND_VAL_EX                                              'Jane'
          9        DO_FCALL                                      0          
         10        ASSIGN                                                   !2, $10
  100    11        NEW                                              $13     'Employee'
         12        SEND_VAL_EX                                              'Jim'
         13        DO_FCALL                                      0          
         14        ASSIGN                                                   !3, $13
  102    15        INIT_METHOD_CALL                                         !0, 'setReference'
         16        SEND_VAL_EX                                              'boss'
         17        SEND_VAR_EX                                              !1
         18        DO_FCALL                                      0          
  103    19        INIT_METHOD_CALL                                         !0, 'setReference'
         20        SEND_VAL_EX                                              'boss'
         21        SEND_VAR_EX                                              !2
         22        DO_FCALL                                      0          
  105    23        ASSERT_CHECK                                             
         24        INIT_FCALL                                               'assert'
         25        INIT_METHOD_CALL                                         !0, 'getReference'
         26        SEND_VAL_EX                                              'boss'
         27        SEND_VAL_EX                                              'Boss'
         28        DO_FCALL                                      0  $18     
         29        IS_IDENTICAL                                     ~19     !2, $18
         30        SEND_VAL                                                 ~19
         31        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27boss%27%2C+Boss%3A%3Aclass%29+%3D%3D%3D+%24bossJane%29'
         32        DO_ICALL                                                 
  106    33        ASSERT_CHECK                                             
         34        INIT_FCALL                                               'assert'
         35        INIT_METHOD_CALL                                         !0, 'getReference'
         36        SEND_VAL_EX                                              'boss'
         37        DO_FCALL                                      0  $21     
         38        IS_IDENTICAL                                     ~22     !2, $21
         39        SEND_VAL                                                 ~22
         40        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27boss%27%29+%3D%3D%3D+%24bossJane%29'
         41        DO_ICALL                                                 
  108    42        INIT_METHOD_CALL                                         !0, 'setReference'
         43        SEND_VAL_EX                                              'person'
         44        SEND_VAR_EX                                              !1
         45        DO_FCALL                                      0          
  109    46        INIT_METHOD_CALL                                         !0, 'setReference'
         47        SEND_VAL_EX                                              'person'
         48        SEND_VAR_EX                                              !3
         49        DO_FCALL                                      0          
  111    50        ASSERT_CHECK                                             
         51        INIT_FCALL                                               'assert'
         52        INIT_METHOD_CALL                                         !0, 'getReference'
         53        SEND_VAL_EX                                              'person'
         54        SEND_VAL_EX                                              'Boss'
         55        DO_FCALL                                      0  $26     
         56        IS_IDENTICAL                                     ~27     !1, $26
         57        SEND_VAL                                                 ~27
         58        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27person%27%2C+Boss%3A%3Aclass%29+%3D%3D%3D+%24bossJohn%29'
         59        DO_ICALL                                                 
  112    60        ASSERT_CHECK                                             
         61        INIT_FCALL                                               'assert'
         62        INIT_METHOD_CALL                                         !0, 'getReference'
         63        SEND_VAL_EX                                              'person'
         64        SEND_VAL_EX                                              'Employee'
         65        DO_FCALL                                      0  $29     
         66        IS_IDENTICAL                                     ~30     !3, $29
         67        SEND_VAL                                                 ~30
         68        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27person%27%2C+Employee%3A%3Aclass%29+%3D%3D%3D+%24employeeJim%29'
         69        DO_ICALL                                                 
  113    70        ASSERT_CHECK                                             
         71        INIT_FCALL                                               'assert'
         72        INIT_METHOD_CALL                                         !0, 'getReference'
         73        SEND_VAL_EX                                              'person'
         74        DO_FCALL                                      0  $32     
         75        IS_IDENTICAL                                     ~33     !3, $32
         76        SEND_VAL                                                 ~33
         77        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27person%27%29+%3D%3D%3D+%24employeeJim%29'
         78        DO_ICALL                                                 
  118    79        INIT_METHOD_CALL                                         !0, 'setReference'
         80        SEND_VAL_EX                                              'number'
         81        SEND_VAL_EX                                              31337
         82        DO_FCALL                                      0          
  119    83        ASSERT_CHECK                                             
         84        INIT_FCALL                                               'assert'
         85        INIT_METHOD_CALL                                         !0, 'getReference'
         86        SEND_VAL_EX                                              'number'
         87        DO_FCALL                                      0  $36     
         88        IS_IDENTICAL                                     ~37     $36, 31337
         89        SEND_VAL                                                 ~37
         90        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27number%27%29+%3D%3D%3D+31337%29'
         91        DO_ICALL                                                 
  120    92        INIT_METHOD_CALL                                         !0, 'setReference'
         93        SEND_VAL_EX                                              'number'
         94        SEND_VAL_EX                                              31337
         95        DO_FCALL                                      0          
  121    96        ASSERT_CHECK                                             
         97        INIT_FCALL                                               'assert'
         98        INIT_METHOD_CALL                                         !0, 'getReference'
         99        SEND_VAL_EX                                              'number'
        100        SEND_VAL_EX                                              'float'
        101        DO_FCALL                                      0  $40     
        102        IS_IDENTICAL                                     ~41     $40, 31337
        103        SEND_VAL                                                 ~41
        104        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27number%27%2C+%27float%27%29+%3D%3D%3D+31337%29'
        105        DO_ICALL                                                 
  124   106        ASSERT_CHECK                                             
        107        INIT_FCALL                                               'assert'
        108        INIT_METHOD_CALL                                         !0, 'getReference'
        109        SEND_VAL_EX                                              'person'
        110        SEND_VAL_EX                                              'Person'
        111        DO_FCALL                                      0  $43     
        112        IS_IDENTICAL                                     ~44     !3, $43
        113        SEND_VAL                                                 ~44
        114        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27person%27%2C+Person%3A%3Aclass%29+%3D%3D%3D+%24employeeJim%29'
        115        DO_ICALL                                                 
  126   116        ASSERT_CHECK                                             
        117        INIT_FCALL                                               'assert'
        118        INIT_METHOD_CALL                                         !0, 'getReference'
        119        SEND_VAL_EX                                              'person'
        120        SEND_VAL_EX                                              'Boss'
        121        DO_FCALL                                      0  $46     
        122        IS_IDENTICAL                                     ~47     !1, $46
        123        SEND_VAL                                                 ~47
        124        SEND_VAL                                                 'assert%28%24repository-%3EgetReference%28%27person%27%2C+Boss%3A%3Aclass%29+%3D%3D%3D+%24bossJohn%29'
        125        DO_ICALL                                                 
  128   126        ECHO                                                     'Success.'
        127      > RETURN                                                   1

Class Repository:
Function setreference:
Finding entry points
Branch analysis from position: 0
2 jumps found. (Code = 43) Position 1 = 7, Position 2 = 14
Branch analysis from position: 7
1 jumps found. (Code = 42) Position 1 = 21
Branch analysis from position: 21
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 14
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/HuZD6
function name:  setReference
number of ops:  25
compiled vars:  !0 = $key, !1 = $identity, !2 = $nsKey
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   16     0  E >   RECV                                             !0      
          1        RECV                                             !1      
   19     2        FETCH_OBJ_W                                      $3      'data'
          3        ASSIGN_DIM                                               $3, !0
          4        OP_DATA                                                  !1
   22     5        TYPE_CHECK                                  256          !1
          6      > JMPZ                                                     ~5, ->14
   23     7    >   INIT_METHOD_CALL                                         'getRealClass'
          8        FETCH_CLASS_NAME                                 ~6      !1
          9        SEND_VAL_EX                                              ~6
         10        DO_FCALL                                      0  $7      
         11        CONCAT                                           ~8      !0, $7
         12        ASSIGN                                                   !2, ~8
   22    13      > JMP                                                      ->21
   25    14    >   INIT_FCALL                                               'get_debug_type'
         15        SEND_VAR                                                 !1
         16        DO_ICALL                                         $10     
         17        COALESCE                                         ~11     $10
         18        QM_ASSIGN                                        ~11     ''
         19        CONCAT                                           ~12     !0, ~11
         20        ASSIGN                                                   !2, ~12
   28    21    >   FETCH_OBJ_W                                      $14     'data'
         22        ASSIGN_DIM                                               $14, !2
         23        OP_DATA                                                  !1
   29    24      > RETURN                                                   null

End of function setreference

Function getreference:
Finding entry points
Branch analysis from position: 0
2 jumps found. (Code = 43) Position 1 = 6, Position 2 = 10
Branch analysis from position: 6
1 jumps found. (Code = 108) Position 1 = -2
Branch analysis from position: 10
2 jumps found. (Code = 43) Position 1 = 12, Position 2 = 15
Branch analysis from position: 12
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 15
2 jumps found. (Code = 43) Position 1 = 23, Position 2 = 27
Branch analysis from position: 23
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 27
2 jumps found. (Code = 46) Position 1 = 31, Position 2 = 36
Branch analysis from position: 31
2 jumps found. (Code = 43) Position 1 = 37, Position 2 = 40
Branch analysis from position: 37
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 40
1 jumps found. (Code = 108) Position 1 = -2
Branch analysis from position: 36
filename:       /in/HuZD6
function name:  getReference
number of ops:  56
compiled vars:  !0 = $key, !1 = $type
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   39     0  E >   RECV                                             !0      
          1        RECV_INIT                                        !1      null
   42     2        FETCH_OBJ_R                                      ~2      'data'
          3        ARRAY_KEY_EXISTS                                 ~3      !0, ~2
          4        BOOL_NOT                                         ~4      ~3
          5      > JMPZ                                                     ~4, ->10
   43     6    >   NEW                                              $5      'Exception'
          7        SEND_VAL_EX                                              'Fixture+not+found'
          8        DO_FCALL                                      0          
          9      > THROW                                         0          $5
   47    10    >   BOOL_NOT                                         ~7      !1
         11      > JMPZ                                                     ~7, ->15
   48    12    >   FETCH_OBJ_R                                      ~8      'data'
         13        FETCH_DIM_R                                      ~9      ~8, !0
         14      > RETURN                                                   ~9
   52    15    >   INIT_FCALL_BY_NAME                                       'array_key_exuists'
         16        CONCAT                                           ~10     !0, !1
         17        SEND_VAL_EX                                              ~10
         18        CHECK_FUNC_ARG                                           
         19        FETCH_OBJ_FUNC_ARG                               $11     'data'
         20        SEND_FUNC_ARG                                            $11
         21        DO_FCALL                                      0  $12     
         22      > JMPZ                                                     $12, ->27
   54    23    >   CONCAT                                           ~14     !0, !1
         24        FETCH_OBJ_R                                      ~13     'data'
         25        FETCH_DIM_R                                      ~15     ~13, ~14
         26      > RETURN                                                   ~15
   62    27    >   INIT_FCALL                                               'class_exists'
         28        SEND_VAR                                                 !1
         29        DO_ICALL                                         $16     
         30      > JMPZ_EX                                          ~17     $16, ->36
         31    >   FETCH_OBJ_R                                      ~18     'data'
         32        FETCH_DIM_R                                      ~19     ~18, !0
         33        FETCH_CLASS                                   0  $20     !1
         34        INSTANCEOF                                       ~21     ~19, $20
         35        BOOL                                             ~17     ~21
         36    > > JMPZ                                                     ~17, ->40
   63    37    >   FETCH_OBJ_R                                      ~22     'data'
         38        FETCH_DIM_R                                      ~23     ~22, !0
         39      > RETURN                                                   ~23
   68    40    >   NEW                                              $24     'Exception'
         41        INIT_FCALL                                               'sprintf'
   69    42        SEND_VAL                                                 'Fixture+%25s+was+found%2C+but+is+type+%25s%2C+not+%25s.+Please+ask+for+the+correct+type.'
   70    43        SEND_VAR                                                 !0
   71    44        INIT_FCALL                                               'get_debug_type'
         45        FETCH_OBJ_R                                      ~25     'data'
         46        FETCH_DIM_R                                      ~26     ~25, !0
         47        SEND_VAL                                                 ~26
         48        DO_ICALL                                         $27     
         49        SEND_VAR                                                 $27
   72    50        SEND_VAR                                                 !1
   68    51        DO_ICALL                                         $28     
   72    52        SEND_VAR_NO_REF_EX                                       $28
   68    53        DO_FCALL                                      0          
   72    54      > THROW                                         0          $24
   74    55*     > RETURN                                                   null

End of function getreference

Function getrealclass:
Finding entry points
Branch analysis from position: 0
2 jumps found. (Code = 43) Position 1 = 7, Position 2 = 13
Branch analysis from position: 7
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 13
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/HuZD6
function name:  getRealClass
number of ops:  15
compiled vars:  !0 = $className
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   76     0  E >   RECV                                             !0      
   78     1        INIT_FCALL                                               'substr'
          2        SEND_VAR                                                 !0
          3        SEND_VAL                                                 -5
          4        DO_ICALL                                         $1      
          5        IS_IDENTICAL                                             $1, 'Proxy'
          6      > JMPZ                                                     ~2, ->13
   79     7    >   INIT_FCALL                                               'substr'
          8        SEND_VAR                                                 !0
          9        SEND_VAL                                                 0
         10        SEND_VAL                                                 -5
         11        DO_ICALL                                         $3      
         12      > RETURN                                                   $3
   82    13    > > RETURN                                                   !0
   83    14*     > RETURN                                                   null

End of function getrealclass

End of class Repository.

Class Person:
Function __construct:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/HuZD6
function name:  __construct
number of ops:  4
compiled vars:  !0 = $name
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   87     0  E >   RECV                                             !0      
          1        ASSIGN_OBJ                                               'name'
          2        OP_DATA                                                  !0
          3      > RETURN                                                   null

End of function __construct

End of class Person.

Class Boss:
Function __construct:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/HuZD6
function name:  __construct
number of ops:  4
compiled vars:  !0 = $name
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
          0  E >   RECV                                             !0      
          1        ASSIGN_OBJ                                               'name'
          2        OP_DATA                                                  !0
          3      > RETURN                                                   null

End of function __construct

End of class Boss.

Class Employee:
Function __construct:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/HuZD6
function name:  __construct
number of ops:  4
compiled vars:  !0 = $name
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
          0  E >   RECV                                             !0      
          1        ASSIGN_OBJ                                               'name'
          2        OP_DATA                                                  !0
          3      > RETURN                                                   null

End of function __construct

End of class Employee.

Generated using Vulcan Logic Dumper, using php 8.0.0


preferences:
148.75 ms | 1455 KiB | 18 Q