====== PHP RFC: Nested Classes ====== * Version: 0.2 * Date: 2013-09-29 * Author: Joe Watkins, krakjoe@php.net * Status: Withdrawn * First Published at: http://wiki.php.net/rfc/nested_classes ===== Introduction ===== Following on from anonymous classes, this RFC proposes we support nested classes in PHP. ===== Proposal ===== A nested class is a class declared in the virtual namespace of another class: class foo { class bar { } } ''foo\bar'' is a nested class in the virtual namespace of ''foo''. A nested class has the ability to declare it's accessibility to other classes in the same way as class members: class foo { public class bar { } } The first and second examples given here are therefore the same, by default classes are public, just like class members. The following describes the functionality of access modifiers for nested classes: * public - the class is accessible everywhere * private - the class may be accessed by any class declared in the //outer// class * protected - the class may be access by any class in the same virtual namespace ===== Private Classes ===== The following example shows how to blackbox some of your functionality in a private nested class: bar = new \foo\bar(); } } var_dump(new \foo()); ?> In the example ''\foo'' is the public facing API, ''\foo\bar'' contains supporting logic never to be exposed outside of ''\foo'', any class declared in the virtual namespace ''\foo'' will be able to access the ''\foo\bar'' class. Attempting: var_dump(new \foo\bar()); will result in Fatal error: Cannot access private class foo\bar from an unknown scope in %s on line %d Private classes are very private, the following example demonstrates this: baz = new foo\bar\baz(); } } /* PUBLIC API METHODS HERE */ public function __construct() { $this->bar = new \foo\bar(); $this->baz = new \foo\bar\baz(); /* line 39 */ } } new \foo(); ?> Output: Fatal error: Cannot access private class foo\bar\baz from foo in %s on line 39 ===== Protecting bits of your Privates ===== The following example shows how protected and private classes can be used in conjunction to provide versatile encapsulation: baz = new foo\bar\baz(); } } /* PUBLIC API METHODS HERE */ public function __construct() { $this->bar = new \foo\bar(); $this->baz = new \foo\bar\baz(); } } var_dump(new \foo()); Output: object(foo)#1 (2) { ["bar"]=> object(foo\bar)#2 (1) { ["baz"]=> object(foo\bar\baz)#3 (0) { } } ["baz"]=> object(foo\bar\baz)#4 (0) { } } The protected class ''\foo\bar\baz'' can now be used in ''\foo'', for example: baz = new foo\bar\baz(); } } /* * \foo\qux supporting class for foo */ private class qux extends foo\bar\baz { public function __construct() { } } /* PUBLIC API METHODS HERE */ public function __construct() { $this->bar = new \foo\bar(); $this->baz = new \foo\bar\baz(); $this->qux = new \foo\qux(); } } var_dump(new \foo()); Output: object(foo)#1 (3) { ["bar"]=> object(foo\bar)#2 (1) { ["baz"]=> object(foo\bar\baz)#3 (0) { } } ["baz"]=> object(foo\bar\baz)#4 (0) { } ["qux"]=> object(foo\qux)#5 (0) { } } ===== Backward Incompatible Changes ===== A single test that was defined in Zend/tests to check that an error is emitted when you declare a nested class; in reality, nothing core is broken. ===== Proposed PHP Version(s) ===== 5.6 ===== SAPIs Impacted ===== All ===== Impact to Existing Extensions ===== Existing libraries that work directly with zend_class_entry structures will need to update to include the additional member of the struct "super"; the member is used to store a pointer to the class that created it. Such an update should not cause any real inconvenience. Reflection requires patching to be able to report information about outer classes and access levels. ===== Open Issues ===== Access to private statics members in outer classes (access to methods requires some adjustment too). ===== Proposed Voting Choices ===== We are not there yet ... ===== Implementation ===== [[https://github.com/krakjoe/php-src/compare/anon_class_objects...nesting_complex ]] ===== References ===== [[https://wiki.php.net/rfc/anonymous_classes]] ===== Rejected Features ===== N/A