rfc:nested_classes

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:nested_classes [2013/09/30 10:14] – [Proposal] krakjoerfc: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: Draft+  * Status: Withdrawn
   * First Published at: http://wiki.php.net/rfc/nested_classes   * First Published at: http://wiki.php.net/rfc/nested_classes
  
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/private/protected, we have the following, simple to enforce and understand rule:+A nested class is a class declared in the virtual namespace of another class:
  
-   * A nested class is only directly available to the class that declares it.+<code php> 
 +class foo { 
 +    class bar { 
 +     
 +    } 
 +
 +</code>
  
-This makes nested classes implicitly private; which is the best use case of a nested class anyway.+''foo\bar'' is a nested class in the virtual namespace of ''foo''
  
-The following is a //use-case-by-example//, it is clearly not the only use case for nested classes; what it shows is the pattern that nesting would allow, the functionality of the example is completely irrelevant:+A nested class has the ability to declare it's accessibility to other classes in the same way as class members:
  
 <code php> <code php>
-<?php +class foo 
-namespace io +    public class bar {
-    interface IOBuffer {}+
          
-    class FileReader { +    
-        class ZipFileReader { +
-            class Buffer implements IOBuffer { +</code> 
-                 + 
-            } +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: 
-        class GzFileReader { + 
-            class Buffer implements IOBuffer +  * 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 class for foo 
 +    * @subpackage \foo\bar 
 +    * @private 
 +    */ 
 +    private class bar 
 +    {
         public function __construct() {         public function __construct() {
-            /* no this is private */ +            /* ... */
-            new FileReader\ZipFileReader\Buffer();+
         }         }
 +    }
 +    
 +    /* PUBLIC API METHODS HERE */
 +    
 +    public function __construct() 
 +    {
 +        $this->bar = new \foo\bar();
     }     }
 } }
  
-namespace { +var_dump(new \foo());
-    var_dump(new io\FileReader()); +
-}+
 ?> ?>
 </code> </code>
  
-The example above will output:+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.
  
-''Fatal errorCannot instantiate private class io\FileReader\ZipFileReader\Buffer from io\FileReader in /usr/src/php-src/nest.php on line 20''+Attempting:
  
-The public API in the example above is io\FileReader, the nested classes are required for FileReader to support multiple different compression types. The compression type classes in turn must define a Buffer object, none of the nested classes are relevant to anything outside of FileReader, therefore it makes sense to nest them and implicitly restrict access to them.+<code php> 
 +var_dump(new \foo\bar()); 
 +</code>
  
-The above is just an example, but this is the general use case of nested classes, shown best with an example.+will result in
  
-Note that only direct access to a nested class is prohibited by this patch, you can however extend a nested class outside of the scope it was nested in+<code> 
- +Fatal error: Cannot access private class foo\bar from an unknown scope in %s on line %d 
-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. Incidentally, this patch makes anonymous classes implicitly private too, because they will be declared with a super class. +</code>
-===== Syntax Example =====+
  
-The following code shows how the current patch requires you to reference nested classes:+Private classes are very private, the following example demonstrates this:
  
 <code php> <code php>
 <?php <?php
-namespace io { +/* 
-    interface IOBuffer {} +* foo 
-     +* @package foo 
-    class FileReader { +*/ 
-        const UNKNOWN = 0; +class foo  
-        const ZIP = 1; +
-        const GZIP = 2;+    /* 
 +    * foo\bar supporting class for foo 
 +    * @subpackage foo\bar 
 +    * @private 
 +    */ 
 +    private class bar 
 +    {
                  
-        class ZipFileReader { +        /* 
-            class Buffer implements IOBuffer { +        * \foo\bar\baz supporting class for foo\bar 
-                /... */ +        @subpackage foo\bar\baz 
-            }+        * @private 
 +        */ 
 +        private class baz  
 +        {
                          
             public function __construct() {             public function __construct() {
-                $this->buffer = new FileReader\ZipFileReader\Buffer(); +                 
-            }+            }    
         }         }
                  
-        class GzFileReader +        public function __construct() 
-            class Buffer implements IOBuffer +            $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(); 
 +?> 
 +</code> 
 + 
 +Output: 
 + 
 +<code> 
 +Fatal error: Cannot access private class foo\bar\baz from foo in %s on line 39 
 +</code> 
 + 
 +===== Protecting bits of your Privates ===== 
 + 
 +The following example shows how protected and private classes can be used in conjunction to provide versatile encapsulation: 
 + 
 +<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->buffer = new FileReader\GzFileReader\Buffer();+ 
             }             }
         }         }
-         +  
-        public function __construct($filename) { +        public function __construct() { 
-            switch (FileReader::getFileType($filename)) { +            $this->baz = new foo\bar\baz(); 
-                case FileReader::ZIP: +        } 
-                    $this->reader = new FileReader\ZipFileReader($filename); +    } 
-                break+  
-                 +    /* PUBLIC API METHODS HERE */ 
-                case FileReader::GZIP: { +  
-                    $this->reader new FileReader\GzFileReader($filename); +    public function __construct() 
-                break; +    
-                 +        $this->bar = new \foo\bar(); 
-                /* ... */+        $this->baz = new \foo\bar\baz(); 
 +    } 
 +
 + 
 +var_dump(new \foo())
 +</code> 
 + 
 +Output: 
 + 
 +<code> 
 +object(foo)#1 (2) 
 +  ["bar"]=> 
 +  object(foo\bar)#2 (1) { 
 +    ["baz"]=
 +    object(foo\bar\baz)#(0{ 
 +    
 +  } 
 +  ["baz"]=> 
 +  object(foo\bar\baz)#4 (0) { 
 +  } 
 +
 +</code> 
 + 
 +The protected class ''\foo\bar\baz'' can now be used in ''\foo'', for example: 
 + 
 +<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 static function getFileType($filename) { +        public function __construct() { 
-            /** .. **/ +            $this->baz = new foo\bar\baz();
-            return FileReader::ZIP;+
         }         }
 +    }
 +    
 +    /*
 +    * \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());
 +</code>
  
-namespace +Output: 
-    var_dump(new io\FileReader($argv[0]));+ 
 +<code> 
 +object(foo)#1 (3) { 
 +  ["bar"]=> 
 +  object(foo\bar)#2 (1) 
 +    ["baz"]=> 
 +    object(foo\bar\baz)#(0) { 
 +    } 
 +  } 
 +  ["baz"]=> 
 +  object(foo\bar\baz)#4 (0) { 
 +  } 
 +  ["qux"]=> 
 +  object(foo\qux)#5 (0
 +  }
 } }
-?> 
 </code> </code>
- 
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
  
Line 142: 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/protected/public, where those keywords have the definition currently used for those keywords (but not yet applied to classes in any case).+Access to private statics members in outer classes (access to methods requires some adjustment too).
  
 ===== Proposed Voting Choices ===== ===== Proposed Voting Choices =====
Line 154: Line 321:
 ===== Implementation ===== ===== Implementation =====
  
-[[https://github.com/krakjoe/php-src/compare/anon_class_objects...nesting+[[https://github.com/krakjoe/php-src/compare/anon_class_objects...nesting_complex
 ]] ]]
  
rfc/nested_classes.1380536081.txt.gz · Last modified: 2017/09/22 13:28 (external edit)