@@ -5854,15 +5854,32 @@ ZEND_VM_HOT_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED|CONST_FETCH, CONST, CACHE_SL
58545854 ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION ();
58555855}
58565856
5857- ZEND_VM_HANDLER (181 , ZEND_FETCH_CLASS_CONSTANT , VAR |CONST |UNUSED |CLASS_FETCH , CONST , CACHE_SLOT )
5857+ // FIXME: Small performance regression due to ANY. Can we make this CONST|ANY?
5858+ ZEND_VM_HANDLER (181 , ZEND_FETCH_CLASS_CONSTANT , VAR |CONST |UNUSED |CLASS_FETCH , ANY , CACHE_SLOT )
58585859{
58595860 zend_class_entry * ce , * scope ;
58605861 zend_class_constant * c ;
58615862 zval * value , * zv ;
5863+ zend_string * constant_name ;
58625864 USE_OPLINE
58635865
58645866 SAVE_OPLINE ();
58655867
5868+ if (OP2_TYPE == IS_CONST ) {
5869+ constant_name = zval_get_string (RT_CONSTANT (opline , opline -> op2 ));
5870+ } else {
5871+ constant_name = zval_get_string (GET_OP2_ZVAL_PTR_DEREF (BP_VAR_R ));
5872+
5873+ if (zend_string_equals_literal_ci (constant_name , "class" )) {
5874+ // FIXME: This should probably just be implemented, since it will work for folded constant expressions
5875+ zend_throw_error (NULL , "Cannot dynamically fetch class constant \"class\"" );
5876+ ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5877+ zend_string_release_ex (constant_name , /* persistent */ false);
5878+ FREE_OP2 ();
5879+ HANDLE_EXCEPTION ();
5880+ }
5881+ }
5882+
58665883 do {
58675884 if (OP1_TYPE == IS_CONST ) {
58685885 if (EXPECTED (CACHED_PTR (opline -> extended_value + sizeof (void * )))) {
@@ -5874,6 +5891,8 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
58745891 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 );
58755892 if (UNEXPECTED (ce == NULL )) {
58765893 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5894+ zend_string_release_ex (constant_name , /* persistent */ false);
5895+ FREE_OP2 ();
58775896 HANDLE_EXCEPTION ();
58785897 }
58795898 }
@@ -5882,6 +5901,8 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
58825901 ce = zend_fetch_class (NULL , opline -> op1 .num );
58835902 if (UNEXPECTED (ce == NULL )) {
58845903 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5904+ zend_string_release_ex (constant_name , /* persistent */ false);
5905+ FREE_OP2 ();
58855906 HANDLE_EXCEPTION ();
58865907 }
58875908 } else {
@@ -5893,19 +5914,24 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
58935914 }
58945915 }
58955916
5896- zv = zend_hash_find_known_hash (CE_CONSTANTS_TABLE (ce ), Z_STR_P (RT_CONSTANT (opline , opline -> op2 )));
5917+ zv = zend_hash_find (CE_CONSTANTS_TABLE (ce ), constant_name );
5918+
58975919 if (EXPECTED (zv != NULL )) {
58985920 c = Z_PTR_P (zv );
58995921 scope = EX (func )-> op_array .scope ;
59005922 if (!zend_verify_const_access (c , scope )) {
5901- 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 ) ));
5923+ 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 ));
59025924 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5925+ zend_string_release_ex (constant_name , /* persistent */ false);
5926+ FREE_OP2 ();
59035927 HANDLE_EXCEPTION ();
59045928 }
59055929
59065930 if (ce -> ce_flags & ZEND_ACC_TRAIT ) {
5907- zend_throw_error (NULL , "Cannot access trait constant %s::%s directly" , ZSTR_VAL (ce -> name ), Z_STRVAL_P ( RT_CONSTANT ( opline , opline -> op2 ) ));
5931+ zend_throw_error (NULL , "Cannot access trait constant %s::%s directly" , ZSTR_VAL (ce -> name ), ZSTR_VAL ( constant_name ));
59085932 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5933+ zend_string_release_ex (constant_name , /* persistent */ false);
5934+ FREE_OP2 ();
59095935 HANDLE_EXCEPTION ();
59105936 }
59115937
@@ -5914,27 +5940,35 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
59145940 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 )) {
59155941 if (UNEXPECTED (zend_update_class_constants (ce ) == FAILURE )) {
59165942 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5943+ zend_string_release_ex (constant_name , /* persistent */ false);
5944+ FREE_OP2 ();
59175945 HANDLE_EXCEPTION ();
59185946 }
59195947 }
59205948 if (Z_TYPE_P (value ) == IS_CONSTANT_AST ) {
59215949 zval_update_constant_ex (value , c -> ce );
59225950 if (UNEXPECTED (EG (exception ) != NULL )) {
59235951 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5952+ zend_string_release_ex (constant_name , /* persistent */ false);
5953+ FREE_OP2 ();
59245954 HANDLE_EXCEPTION ();
59255955 }
59265956 }
59275957 CACHE_POLYMORPHIC_PTR (opline -> extended_value , ce , value );
59285958 } else {
59295959 zend_throw_error (NULL , "Undefined constant %s::%s" ,
5930- ZSTR_VAL (ce -> name ), Z_STRVAL_P ( RT_CONSTANT ( opline , opline -> op2 ) ));
5960+ ZSTR_VAL (ce -> name ), ZSTR_VAL ( constant_name ));
59315961 ZVAL_UNDEF (EX_VAR (opline -> result .var ));
5962+ zend_string_release_ex (constant_name , /* persistent */ false);
5963+ FREE_OP2 ();
59325964 HANDLE_EXCEPTION ();
59335965 }
59345966 } while (0 );
59355967
59365968 ZVAL_COPY_OR_DUP (EX_VAR (opline -> result .var ), value );
59375969
5970+ zend_string_release_ex (constant_name , /* persistent */ false);
5971+ FREE_OP2 ();
59385972 ZEND_VM_NEXT_OPCODE ();
59395973}
59405974
0 commit comments