rfc:nested_classes
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:nested_classes [2013/09/29 17:56] – [Proposal] krakjoe | rfc:nested_classes [2017/09/22 13:28] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Nested Classes ====== | ====== PHP RFC: Nested Classes ====== | ||
- | * Version: 0.1 | + | * Version: 0.2 |
* Date: 2013-09-29 | * Date: 2013-09-29 | ||
* Author: Joe Watkins, krakjoe@php.net | * Author: Joe Watkins, krakjoe@php.net | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
Line 13: | Line 13: | ||
===== Proposal ===== | ===== Proposal ===== | ||
- | I propose that we have the simplest version of class nesting that is useful, rather than creating new access checking routines and declaring public/ | + | A nested |
- | * A nested | + | <code php> |
- | | + | class foo { |
- | This makes nested classes implicitly private; which is the best use case of a nested class anyway. | + | |
+ | |||
+ | } | ||
+ | } | ||
+ | </ | ||
- | The following | + | '' |
+ | |||
+ | A nested | ||
<code php> | <code php> | ||
- | <?php | + | class foo { |
- | namespace io { | + | |
- | | + | |
| | ||
- | class FileReader { | + | |
- | class ZipFileReader | + | } |
- | class Buffer implements IOBuffer | + | </ |
- | + | ||
- | | + | 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: | ||
+ | |||
+ | <code php> | ||
+ | <?php | ||
+ | /* | ||
+ | * \foo | ||
+ | * @package \foo | ||
+ | */ | ||
+ | class foo | ||
+ | { | ||
+ | /* | ||
+ | * \foo\bar supporting | ||
+ | * @subpackage \foo\bar | ||
+ | * @private | ||
+ | */ | ||
+ | private class bar | ||
+ | | ||
+ | | ||
+ | | ||
} | } | ||
+ | } | ||
+ | | ||
+ | /* PUBLIC API METHODS HERE */ | ||
+ | | ||
+ | public function __construct() | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var_dump(new \foo()); | ||
+ | ?> | ||
+ | </ | ||
+ | |||
+ | In the example '' | ||
+ | |||
+ | Attempting: | ||
+ | |||
+ | <code php> | ||
+ | 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: | ||
+ | |||
+ | <code php> | ||
+ | <?php | ||
+ | /* | ||
+ | * foo | ||
+ | * @package foo | ||
+ | */ | ||
+ | class foo | ||
+ | { | ||
+ | /* | ||
+ | * foo\bar supporting class for foo | ||
+ | * @subpackage foo\bar | ||
+ | * @private | ||
+ | */ | ||
+ | private class bar | ||
+ | { | ||
| | ||
- | class GzFileReader | + | |
- | | + | * \foo\bar\baz supporting |
+ | * @subpackage foo\bar\baz | ||
+ | * @private | ||
+ | */ | ||
+ | private class baz | ||
+ | | ||
+ | | ||
+ | public function __construct() | ||
| | ||
- | } | + | } |
} | } | ||
| | ||
public function __construct() { | public function __construct() { | ||
- | | + | |
- | | + | |
} | } | ||
+ | } | ||
+ | | ||
+ | /* PUBLIC API METHODS HERE */ | ||
+ | | ||
+ | public function __construct() | ||
+ | { | ||
+ | $this-> | ||
+ | $this-> | ||
} | } | ||
} | } | ||
- | namespace { | + | new \foo(); |
- | var_dump(new io\FileReader()); | + | |
- | } | + | |
?> | ?> | ||
</ | </ | ||
- | The example above will output: | + | Output: |
- | '' | + | < |
+ | Fatal error: Cannot | ||
+ | </ | ||
- | The public API in the example above is io\FileReader, | + | ===== Protecting bits of your Privates ===== |
- | The above is just an example, but this is the general use case of nested | + | The following |
- | Note that only direct access to a nested | + | <code php> |
+ | <?php | ||
+ | /* | ||
+ | * foo | ||
+ | * @package foo | ||
+ | */ | ||
+ | class foo | ||
+ | { | ||
+ | /* | ||
+ | * foo\bar supporting | ||
+ | * @subpackage foo\bar | ||
+ | * @private | ||
+ | */ | ||
+ | private class bar | ||
+ | { | ||
+ | |||
+ | /* | ||
+ | * \foo\bar\baz supporting class for foo\bar | ||
+ | * @subpackage foo\bar\baz | ||
+ | * @protected | ||
+ | */ | ||
+ | protected class baz | ||
+ | { | ||
+ | |||
+ | public function __construct() { | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | public function __construct() { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* PUBLIC API METHODS HERE */ | ||
+ | |||
+ | public function __construct() | ||
+ | { | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
- | The reason this proposal is built on top of the anonymous classes RFC is because anonymous classes require support for nesting at the compiler, this patch just exposes a way to formally nest named classes. The same idea can be implemented independent of anonymous classes. The same thing could be implemented independent of anonymous classes. Incidentally, this patch makes anonymous classes implicitly | + | var_dump(new \foo()); |
+ | </ | ||
+ | |||
+ | Output: | ||
+ | |||
+ | < | ||
+ | object(foo)# | ||
+ | [" | ||
+ | object(foo\bar)# | ||
+ | [" | ||
+ | object(foo\bar\baz)# | ||
+ | } | ||
+ | } | ||
+ | [" | ||
+ | object(foo\bar\baz)# | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The protected class '' | ||
+ | |||
+ | <code php> | ||
+ | <?php | ||
+ | /* | ||
+ | * foo | ||
+ | * @package foo | ||
+ | */ | ||
+ | class foo | ||
+ | { | ||
+ | /* | ||
+ | * foo\bar supporting class for foo | ||
+ | * @subpackage foo\bar | ||
+ | * @private | ||
+ | */ | ||
+ | private class bar | ||
+ | { | ||
+ | |||
+ | /* | ||
+ | * \foo\bar\baz supporting class for foo\bar | ||
+ | * @subpackage foo\bar\baz | ||
+ | * @protected | ||
+ | */ | ||
+ | protected class baz | ||
+ | { | ||
+ | |||
+ | public function __construct() { | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | public function __construct() { | ||
+ | $this->baz = new foo\bar\baz(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * \foo\qux supporting class for foo | ||
+ | */ | ||
+ | | ||
+ | { | ||
+ | public function __construct() { | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | /* PUBLIC API METHODS HERE */ | ||
+ | |||
+ | public function __construct() | ||
+ | { | ||
+ | $this-> | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var_dump(new \foo()); | ||
+ | </ | ||
+ | |||
+ | Output: | ||
+ | |||
+ | < | ||
+ | object(foo)# | ||
+ | [" | ||
+ | object(foo\bar)# | ||
+ | [" | ||
+ | object(foo\bar\baz)# | ||
+ | } | ||
+ | } | ||
+ | [" | ||
+ | object(foo\bar\baz)# | ||
+ | } | ||
+ | [" | ||
+ | object(foo\qux)# | ||
+ | } | ||
+ | } | ||
+ | </ | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 81: | Line 309: | ||
Such an update should not cause any real inconvenience. | Such an update should not cause any real inconvenience. | ||
- | ===== Open Issues ===== | + | Reflection requires patching to be able to report information about outer classes and access levels. |
- | Is this the right route to take, should we consider it at all, should we pursue more complex support of nested classes. | + | ===== Open Issues ===== |
- | By more complex I mean; the use and enforcement of private/ | + | Access to private |
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
Line 93: | Line 321: | ||
===== Implementation ===== | ===== Implementation ===== | ||
- | [[https:// | + | [[https:// |
]] | ]] | ||
rfc/nested_classes.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1