@@ -368,8 +368,14 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c
368368 uintptr_t offset ;
369369
370370 if (cache_slot && EXPECTED (ce == CACHED_PTR_EX (cache_slot ))) {
371- * info_ptr = CACHED_PTR_EX (cache_slot + 2 );
372- return (uintptr_t )CACHED_PTR_EX (cache_slot + 1 );
371+ const zend_property_info * cached_prop_info = CACHED_PTR_EX (cache_slot + 2 );
372+ /* Disable caching for namespace_private properties since visibility depends on caller's namespace */
373+ if (UNEXPECTED (cached_prop_info && (cached_prop_info -> flags & ZEND_ACC_NAMESPACE_PRIVATE ))) {
374+ /* Fall through to do the visibility check */
375+ } else {
376+ * info_ptr = cached_prop_info ;
377+ return (uintptr_t )CACHED_PTR_EX (cache_slot + 1 );
378+ }
373379 }
374380
375381 if (UNEXPECTED (zend_hash_num_elements (& ce -> properties_info ) == 0 )
@@ -391,6 +397,7 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c
391397 property_info = (zend_property_info * )Z_PTR_P (zv );
392398 flags = property_info -> flags ;
393399
400+
394401 if (flags & (ZEND_ACC_CHANGED |ZEND_ACC_PRIVATE |ZEND_ACC_PROTECTED |ZEND_ACC_NAMESPACE_PRIVATE )) {
395402 const zend_class_entry * scope = get_fake_or_executed_scope ();
396403
@@ -410,30 +417,36 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c
410417 goto found ;
411418 }
412419 }
413- if (flags & ZEND_ACC_PRIVATE ) {
414- if (property_info -> ce != ce ) {
415- goto dynamic ;
416- } else {
420+ /* Check private/protected, but not namespace_private (handled separately below) */
421+ if (!(flags & ZEND_ACC_NAMESPACE_PRIVATE )) {
422+ if (flags & ZEND_ACC_PRIVATE ) {
423+ if (property_info -> ce != ce ) {
424+ goto dynamic ;
425+ } else {
417426wrong :
418- /* Information was available, but we were denied access. Error out. */
419- if (!silent ) {
420- zend_bad_property_access (property_info , ce , member );
427+ /* Information was available, but we were denied access. Error out. */
428+ if (!silent ) {
429+ zend_bad_property_access (property_info , ce , member );
430+ }
431+ return ZEND_WRONG_PROPERTY_OFFSET ;
432+ }
433+ } else {
434+ ZEND_ASSERT (flags & ZEND_ACC_PROTECTED );
435+ if (UNEXPECTED (!is_protected_compatible_scope (property_info -> prototype -> ce , scope ))) {
436+ goto wrong ;
421437 }
422- return ZEND_WRONG_PROPERTY_OFFSET ;
423438 }
424- } else if (flags & ZEND_ACC_NAMESPACE_PRIVATE ) {
425- /* Check namespace visibility */
426- zend_string * property_namespace = zend_get_class_namespace (property_info -> ce );
427- zend_string * caller_namespace = zend_get_caller_namespace ();
439+ }
440+ }
428441
429- if (! zend_string_equals ( property_namespace , caller_namespace )) {
430- goto wrong ;
431- }
432- } else {
433- ZEND_ASSERT ( flags & ZEND_ACC_PROTECTED );
434- if ( UNEXPECTED (! is_protected_compatible_scope ( property_info -> prototype -> ce , scope ))) {
435- goto wrong ;
436- }
442+ /* Check namespace visibility (must be outside scope check) */
443+ if ( flags & ZEND_ACC_NAMESPACE_PRIVATE ) {
444+ zend_string * property_namespace = zend_get_class_namespace ( property_info -> ce );
445+ zend_string * caller_namespace = zend_get_caller_namespace ();
446+
447+
448+ if (! zend_string_equals ( property_namespace , caller_namespace )) {
449+ goto wrong ;
437450 }
438451 }
439452 }
@@ -513,30 +526,36 @@ ZEND_API zend_property_info *zend_get_property_info(const zend_class_entry *ce,
513526 goto found ;
514527 }
515528 }
516- if (flags & ZEND_ACC_PRIVATE ) {
517- if (property_info -> ce != ce ) {
518- goto dynamic ;
519- } else {
529+ /* Check private/protected, but not namespace_private (handled separately below) */
530+ if (!(flags & ZEND_ACC_NAMESPACE_PRIVATE )) {
531+ if (flags & ZEND_ACC_PRIVATE ) {
532+ if (property_info -> ce != ce ) {
533+ goto dynamic ;
534+ } else {
520535wrong :
521- /* Information was available, but we were denied access. Error out. */
522- if (!silent ) {
523- zend_bad_property_access (property_info , ce , member );
536+ /* Information was available, but we were denied access. Error out. */
537+ if (!silent ) {
538+ zend_bad_property_access (property_info , ce , member );
539+ }
540+ return ZEND_WRONG_PROPERTY_INFO ;
541+ }
542+ } else {
543+ ZEND_ASSERT (flags & ZEND_ACC_PROTECTED );
544+ if (UNEXPECTED (!is_protected_compatible_scope (property_info -> prototype -> ce , scope ))) {
545+ goto wrong ;
524546 }
525- return ZEND_WRONG_PROPERTY_INFO ;
526547 }
527- } else if (flags & ZEND_ACC_NAMESPACE_PRIVATE ) {
528- /* Check namespace visibility */
529- zend_string * property_namespace = zend_get_class_namespace (property_info -> ce );
530- zend_string * caller_namespace = zend_get_caller_namespace ();
548+ }
549+ }
531550
532- if (! zend_string_equals ( property_namespace , caller_namespace )) {
533- goto wrong ;
534- }
535- } else {
536- ZEND_ASSERT ( flags & ZEND_ACC_PROTECTED );
537- if ( UNEXPECTED (! is_protected_compatible_scope ( property_info -> prototype -> ce , scope ))) {
538- goto wrong ;
539- }
551+ /* Check namespace visibility (must be outside scope check) */
552+ if ( flags & ZEND_ACC_NAMESPACE_PRIVATE ) {
553+ zend_string * property_namespace = zend_get_class_namespace ( property_info -> ce );
554+ zend_string * caller_namespace = zend_get_caller_namespace ();
555+
556+
557+ if (! zend_string_equals ( property_namespace , caller_namespace )) {
558+ goto wrong ;
540559 }
541560 }
542561 }
@@ -1913,13 +1932,16 @@ ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *
19131932 goto exit ;
19141933 }
19151934 }
1916- if (UNEXPECTED (fbc -> op_array .fn_flags & ZEND_ACC_PRIVATE )
1917- || UNEXPECTED (!zend_check_protected (zend_get_function_root_class (fbc ), scope ))) {
1918- if (zobj -> ce -> __call ) {
1919- fbc = zend_get_call_trampoline_func (zobj -> ce -> __call , method_name );
1920- } else {
1921- zend_bad_method_call (fbc , method_name , scope );
1922- fbc = NULL ;
1935+ /* Check private/protected, but not namespace_private (handled separately below) */
1936+ if (!(fbc -> op_array .fn_flags & ZEND_ACC_NAMESPACE_PRIVATE )) {
1937+ if (UNEXPECTED (fbc -> op_array .fn_flags & ZEND_ACC_PRIVATE )
1938+ || UNEXPECTED (!zend_check_protected (zend_get_function_root_class (fbc ), scope ))) {
1939+ if (zobj -> ce -> __call ) {
1940+ fbc = zend_get_call_trampoline_func (zobj -> ce -> __call , method_name );
1941+ } else {
1942+ zend_bad_method_call (fbc , method_name , scope );
1943+ fbc = NULL ;
1944+ }
19231945 }
19241946 }
19251947 }
0 commit comments