rfc:nested_classes

This is an old revision of the document!


PHP RFC: Nested Classes

Introduction

Following on from anonymous classes, this RFC proposes we support nested classes in PHP.

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 only directly available to the class that declares it.

This makes nested classes implicitly private; which is the best use case of a nested class anyway.

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:

<?php
namespace io {
    interface IOBuffer {}
 
    class FileReader {
        class ZipFileReader {
            class Buffer implements IOBuffer {
 
            }
        }
 
        class GzFileReader {
            class Buffer implements IOBuffer {
 
            }
        }
 
        public function __construct() {
            /* no this is private */
            new FileReader\ZipFileReader\Buffer();
        }
    }
}
 
namespace {
    var_dump(new io\FileReader());
}
?>

The example above will output:

Fatal error: Cannot instantiate private class io\FileReader\ZipFileReader\Buffer from io\FileReader in /usr/src/php-src/nest.php on line 20

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.

The above is just an example, but this is the general use case of nested classes, shown best with an example.

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.

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.

Syntax Example

The following code shows how the current patch requires you to reference nested classes:

<?php
namespace io {
    interface IOBuffer {}
 
    class FileReader {
        const UNKNOWN = 0;
        const ZIP = 1;
        const GZIP = 2;
 
        class ZipFileReader {
            class Buffer implements IOBuffer {
                /* ... */
            }
 
            public function __construct() {
                $this->buffer = new FileReader\ZipFileReader\Buffer();
            }
        }
 
        class GzFileReader {
            class Buffer implements IOBuffer {
                /* ... */
            }
 
            public function __construct() {
                $this->buffer = new FileReader\GzFileReader\Buffer();
            }
        }
 
        public function __construct($filename) {
            switch (FileReader::getFileType($filename)) {
                case FileReader::ZIP: {
                    $this->reader = new FileReader\ZipFileReader($filename);
                } break;
 
                case FileReader::GZIP: {
                    $this->reader = new FileReader\GzFileReader($filename);
                } break;
 
                /* ... */
            }
        }
 
        public static function getFileType($filename) {
            /** .. **/
            return FileReader::ZIP;
        }
    }
}
 
namespace {
    var_dump(new io\FileReader($argv[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.

Open Issues

Is this the right route to take, should we consider it at all, should we pursue more complex support of nested classes.

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).

Proposed Voting Choices

We are not there yet ...

Implementation

References

Rejected Features

N/A

rfc/nested_classes.1380535706.txt.gz · Last modified: 2017/09/22 13:28 (external edit)