@@ -5853,15 +5853,40 @@ ZEND_VM_HOT_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED|CONST_FETCH, CONST, CACHE_SL
58535853 ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION ();
58545854}
58555855
5856- ZEND_VM_HANDLER (181 , ZEND_FETCH_CLASS_CONSTANT , VAR |CONST |UNUSED |CLASS_FETCH , CONST , CACHE_SLOT )
5856+ // FIXME: Small performance regression due to ANY. Can we make this CONST|ANY?
5857+ ZEND_VM_HANDLER (181 , ZEND_FETCH_CLASS_CONSTANT , VAR |CONST |UNUSED |CLASS_FETCH , ANY , CACHE_SLOT )
58575858{
58585859 zend_class_entry * ce , * scope ;
58595860 zend_class_constant * c ;
58605861 zval * value , * zv ;
5862+ zend_string * constant_name ;
58615863 USE_OPLINE
58625864
58635865 SAVE_OPLINE ();
58645866
5867+ if (OP2_TYPE == IS_CONST ) {
5868+ // FIXME: Unreachable for now, check if we can add this specialization
5869+ constant_name = Z_STR_P (RT_CONSTANT (opline , opline -> op2 ));
5870+ } else {
5871+ zval * op2 = GET_OP2_ZVAL_PTR_DEREF (BP_VAR_R );
5872+ if (!try_convert_to_string (op2 )) {
5873+ zend_throw_error (NULL , "Illegal offset type" );
5874+ ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5875+ FREE_OP2 ();
5876+ HANDLE_EXCEPTION ();
5877+ }
5878+ constant_name = Z_STR_P (op2 );
5879+ // FIXME: Not sure when hashes are calculated and why this is necessary only here
5880+ zend_string_hash_val (constant_name );
5881+
5882+ if (zend_string_equals_literal_ci (constant_name , "class" )) {
5883+ // FIXME: This should probably just be implemented, since it will work for folded constant expressions
5884+ zend_throw_error (NULL , "Cannot dynamically fetch class constant \"class\"" );
5885+ FREE_OP2 ();
5886+ HANDLE_EXCEPTION ();
5887+ }
5888+ }
5889+
58655890 do {
58665891 if (OP1_TYPE == IS_CONST ) {
58675892 if (EXPECTED (CACHED_PTR (opline -> extended_value + sizeof (void * )))) {
@@ -5873,6 +5898,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
58735898 ce = zend_fetch_class_by_name (Z_STR_P (RT_CONSTANT (opline , opline -> op1 )), Z_STR_P (RT_CONSTANT (opline , opline -> op1 ) + 1 ), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION );
58745899 if (UNEXPECTED (ce == NULL )) {
58755900 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5901+ FREE_OP2 ();
58765902 HANDLE_EXCEPTION ();
58775903 }
58785904 }
@@ -5881,6 +5907,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
58815907 ce = zend_fetch_class (NULL , opline -> op1 .num );
58825908 if (UNEXPECTED (ce == NULL )) {
58835909 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5910+ FREE_OP2 ();
58845911 HANDLE_EXCEPTION ();
58855912 }
58865913 } else {
@@ -5892,19 +5919,21 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
58925919 }
58935920 }
58945921
5895- zv = zend_hash_find_known_hash (CE_CONSTANTS_TABLE (ce ), Z_STR_P ( RT_CONSTANT ( opline , opline -> op2 )) );
5922+ zv = zend_hash_find_known_hash (CE_CONSTANTS_TABLE (ce ), constant_name );
58965923 if (EXPECTED (zv != NULL )) {
58975924 c = Z_PTR_P (zv );
58985925 scope = EX (func )-> op_array .scope ;
58995926 if (!zend_verify_const_access (c , scope )) {
5900- zend_throw_error (NULL , "Cannot access %s constant %s::%s" , zend_visibility_string (ZEND_CLASS_CONST_FLAGS (c )), ZSTR_VAL (ce -> name ), Z_STRVAL_P ( RT_CONSTANT ( opline , opline -> op2 ) ));
5927+ zend_throw_error (NULL , "Cannot access %s constant %s::%s" , zend_visibility_string (ZEND_CLASS_CONST_FLAGS (c )), ZSTR_VAL (ce -> name ), ZSTR_VAL ( constant_name ));
59015928 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5929+ FREE_OP2 ();
59025930 HANDLE_EXCEPTION ();
59035931 }
59045932
59055933 if (ce -> ce_flags & ZEND_ACC_TRAIT ) {
5906- zend_throw_error (NULL , "Cannot access trait constant %s::%s directly" , ZSTR_VAL (ce -> name ), Z_STRVAL_P ( RT_CONSTANT ( opline , opline -> op2 ) ));
5934+ zend_throw_error (NULL , "Cannot access trait constant %s::%s directly" , ZSTR_VAL (ce -> name ), ZSTR_VAL ( constant_name ));
59075935 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5936+ FREE_OP2 ();
59085937 HANDLE_EXCEPTION ();
59095938 }
59105939
@@ -5913,27 +5942,31 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
59135942 if (ce -> ce_flags & ZEND_ACC_ENUM && ce -> enum_backing_type != IS_UNDEF && ce -> type == ZEND_USER_CLASS && !(ce -> ce_flags & ZEND_ACC_CONSTANTS_UPDATED )) {
59145943 if (UNEXPECTED (zend_update_class_constants (ce ) == FAILURE )) {
59155944 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5945+ FREE_OP2 ();
59165946 HANDLE_EXCEPTION ();
59175947 }
59185948 }
59195949 if (Z_TYPE_P (value ) == IS_CONSTANT_AST ) {
59205950 zval_update_constant_ex (value , c -> ce );
59215951 if (UNEXPECTED (EG (exception ) != NULL )) {
59225952 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5953+ FREE_OP2 ();
59235954 HANDLE_EXCEPTION ();
59245955 }
59255956 }
59265957 CACHE_POLYMORPHIC_PTR (opline -> extended_value , ce , value );
59275958 } else {
59285959 zend_throw_error (NULL , "Undefined constant %s::%s" ,
5929- ZSTR_VAL (ce -> name ), Z_STRVAL_P ( RT_CONSTANT ( opline , opline -> op2 ) ));
5960+ ZSTR_VAL (ce -> name ), ZSTR_VAL ( constant_name ));
59305961 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5962+ FREE_OP2 ();
59315963 HANDLE_EXCEPTION ();
59325964 }
59335965 } while (0 );
59345966
59355967 ZVAL_COPY_OR_DUP (EX_VAR (opline -> result .var ), value );
59365968
5969+ FREE_OP2 ();
59375970 ZEND_VM_NEXT_OPCODE ();
59385971}
59395972
0 commit comments