rfc:encapsulation

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

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

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