====== PHP RFC: Encapsulation ====== * Version: 0.1 * Date: 2015-02-19 * Author: Leigh, leigh@php.net (Draft RFC) & Guilherme Blanco, guilhermeblanco@php.net (Implementation) * Status: Draft * First Published at: https://wiki.php.net/rfc/encapsulation ===== Introduction ===== This RFC proposes the introduction of encapsulation to classes, interfaces and traits within a namespace. ===== Proposal ===== 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. ==== New Behaviour ==== * Private classes can only be instantiated and extended within their defining namespace. * Private interfaces can only be implemented and extended within their defining namespace. * Private traits can only be extended and used in classes that are also defined within the same namespace. * Attempting to access a private class, interface or trait out of scope results in a fatal error. ==== Unchanged Behaviour ==== 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. ==== Reflection ==== The following reflection methods have been implemented in the patch * ReflectionClass::isPublic() * ReflectionClass::isPrivate() * ReflectionClass::setAccessible() ==== Auto-loading ==== Private visibility is respected when auto-loading is triggered from an invalid namespace. ==== Examples ==== 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 } ===== Backward Incompatible Changes ===== There are no backward incompatible changes. No new keywords are introduced and the default visibility of classes remains ''public''. ===== Proposed PHP Version(s) ===== 7.0 ===== RFC Impact ===== ==== To SAPIs ==== All SAPIs are affected equally. They gain the new behaviour and do not suffer any breaks. ==== To Existing Extensions ==== No existing extensions are affected, as this behaviour is not available to them yet. ==== To Opcache ==== There are no new opcodes, and checks are performed at compile time as well as runtime. ===== Open Issues ===== * I didn't see any special handling for ''clone'' in the patch, and have raised this with Guilherme ===== Future Scope ===== 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. ===== Proposed Voting Choices ===== 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. ===== Patches and Tests ===== 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. ===== References ===== * [[http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29|The Wikipedia article on Encapsulation]] * [[https://msdn.microsoft.com/en-us/library/dd460654.aspx#AccessModifiers|Access Modifiers in C#]] * [[http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html|Package Visibility in Java]]