This RFC proposes the introduction of encapsulation to classes, interfaces and traits within a namespace.
Since PHP 5.3 namespaces have been used as a tool to organise related pieces of functionality into named units. However it is often the case that not all of the functionality contained within a namespace is required to be exposed and accessible to other parts of the program, even if a well documented and complete API is presented a developer may still access the inner-most parts of the module.
With the application of encapsulation a developer trying to directly access functionality that was intended to only be used within the scope of the module (a helper class or utility function) will be denied this access, and it will serve as an indication that they are attempting to do something outside of the intended design.
This proposal is limited to the private visibility of classes, interfaces and traits, reusing the existing private
keyword. There is plenty of room for future scope if the community decides that this type of functionality is desirable on the whole.
Outside of the new behaviour introduced using the private
keyword, other behaviour remains untouched. For example, once a private class has been instantiated the object can be returned to a caller in any namespace, and the methods and properties of an are accessible just as they would be for a public class. Private classes and interfaces can still be used for parameter hinting in any namespace, and checks such as implements
can be used with them.
The following reflection methods have been implemented in the patch
Private visibility is respected when auto-loading is triggered from an invalid namespace.
Instantiating a private class from an invalid scope
namespace Foo { private class Bar {} function giveMeBar() { return new Bar; } } $foobar = \Foo\giveMeBar(); // This is fine $foobar = new \Foo\Bar; // This is a fatal error
Extending a private class from an invalid scope
namespace Foo { private class Bar {} } namespace Baz { class Qux extends \Foo\Bar {} // This is a fatal error }
Implementing a private interface from an invalid scope
namespace Foo { private interface Bar {} } namespace Baz { class Qux implements \Foo\Bar {} // This is a fatal error }
There are no backward incompatible changes. No new keywords are introduced and the default visibility of classes remains public
.
7.0
All SAPIs are affected equally. They gain the new behaviour and do not suffer any breaks.
No existing extensions are affected, as this behaviour is not available to them yet.
There are no new opcodes, and checks are performed at compile time as well as runtime.
clone
in the patch, and have raised this with Guilherme
There is future scope for similar behaviour to be applied to functions within a namespace, as well as the potential to use the protected
keyword. However as these enhancements are likely to lead to extended debate, they should be covered in a separate RFC.
As a change to the functionality of the core language, this RFC requires at least 2/3 of the votes to be in favour of the proposal to pass.
A complete implementation is available: https://github.com/php/php-src/pull/947
This is considered to be a near-final patch, unless significant changes are required or bugs identified during the RFC process.