rfc:class-like_primitive_types

This is an old revision of the document!


PHP RFC: Class-like Primitive Types

Background

PHP has a small set of built-in types of value: null, Boolean, integer, float, string, array, object and resource. These types are known as “primitive” types, because they are built-in to the language. Of these, objects are special. Objects, themselves an instance of the primitive type object, are also instances of PHP's form of non-primitive, user-defined types: classes.

Since their introduction in PHP 3.0, classes and objects have gained several features that are exclusive to them, which the other primitive types consequently cannot make use of. These features include instance and static methods, properties, class constants, interface implementation, inheritance, and instanceof.

This set of exclusive features creates an awkward divide between PHP's objects and its other primitive types. Various tasks must be done in different ways for objects versus other types, creating the need for workarounds to bridge the gap. For example, the iterable pseudo-type was introduced because objects can implement Traversable, yet the array type, not being a class, cannot.

By contrast, some of PHP's contemporaries, like JavaScript and Python, make all their primitive types be classes. This brings uniformity, and also means primitive types can benefit from the convenience of method calls as compared to function calls.

There could be benefits to adopting the same approach in PHP. However, as of PHP 5, PHP objects behave differently from the other primitive types, in that they are not value types, but rather reference types. This prevents making the other primitive types into objects, unless objects were changed to also support value type semantics. Even surmounting that hurdle, the PHP interpreter's internal representation of objects versus other primitive values is much less efficient, so replacing the primitive types with classes could significantly reduce performance. Moreover, changing the internal representation of the other primitive types in the PHP interpreter would be a massive undertaking.

Hence, this RFC suggests a different approach.

Proposal

This RFC proposes to extend PHP's object-oriented features to the other primitive types. They would not become objects, and their internal representation would be unchanged. However, they would now benefit from most of the features of objects.

Features

The following features of objects would now be extended to the other primitive types:

  • Interfaces - These types will now implement PHP's pre-defined interfaces as appropriate (Serializable, Iterator, Traversable, etc.)
  • Inheritance - At present this would go unused, but in future it would be possible to, for example, make int and float extend \Number
  • instanceof - This will no longer throw a fatal error when given non-objects, will return TRUE as appropriate for interfaces or extended classes, and will now support checking for instances of primitive types (e.g. $foobar instanceof int)
  • Type declaration checks for interfaces and inheritance - As with instanceof
  • Instance methods - These types will provide instance methods as necessary to conform to PHP's pre-defined interfaces (->serialize() etc.), and could provide other methods in future (e.g. string or array manipulation methods)
  • Instance properties - At present none would be added, and the types would not support adding undefined properties, but these types could provide magic properties in future (e.g. ->length on an array or string)

The following features would not now be extended to the other primitive types:

  • is_object() will continue to return FALSE for the other primitive types
  • gettype() will continue to report the other primitive types as non-objects
  • ArrayAccess will not be implemented by array<php>, because it provides mutating methods   **FIXME:** What do I do about reflection?   ==== Primitive type class hierarchy ====   Behind each other primitive types, there would now be a hidden internal class, or //shadow class//. Attempts to call methods, look up properties, use <php>instanceof, etc. on primitive values would consult these hidden internal classes. The following is an outline of these new classes.
final class null implements Serializable {
    public function __toString() { /* ... */ }
    public function __debugInfo() { /* ... */ }
    public function serialize() { /* ... */ }
    public function unserialize($serialized) { /* ... */ }
}
final class bool implements Serializable {
    public function __toString() { /* ... */ }
    public function __debugInfo() { /* ... */ }
    public function serialize() { /* ... */ }
    public function unserialize($serialized) { /* ... */ }
}
final class int implements Serializable {
    public function __toString() { /* ... */ }
    public function __debugInfo() { /* ... */ }
    public function serialize() { /* ... */ }
    public function unserialize($serialized) { /* ... */ }
}
final class float implements Serializable {
    public function __toString() { /* ... */ }
    public function __debugInfo() { /* ... */ }
    public function serialize() { /* ... */ }
    public function unserialize($serialized) { /* ... */ }
}
final class string implements Serializable {
    public function __toString() { /* ... */ }
    public function __debugInfo() { /* ... */ }
    public function serialize() { /* ... */ }
    public function unserialize($serialized) { /* ... */ }
}
final class array implements Serializable, Countable, IteratorAggregate {
    public function __toString() { /* ... */ }
    public function __debugInfo() { /* ... */ }
    public function serialize() { /* ... */ }
    public function unserialize($serialized) { /* ... */ }
    public function count() { /* ... */ }
    public function getIterator() {
        return new ArrayIterator($this);
    }
}
final class resource implements Serializable {
    public function __toString() { /* ... */ }
    public function __debugInfo() { /* ... */ }
    public function serialize() { /* ... */ }
    public function unserialize($serialized) { /* ... */ }
}

Backward Incompatible Changes

FIXME

Proposed PHP Version(s)

This is proposed for the next PHP 7.x. Currently, that would be PHP 7.2.

RFC Impact

To SAPIs

This has no particular special impact on the SAPIs.

To Existing Extensions

This does not impact existing extensions, their view of the world is unchanged and the other primitive types are still primitives.

FIXME: Reflection.

To Opcache

FIXME.

Open Issues

FIXME: Reflection, Opcache.

Unaffected PHP Functionality

FIXME

Future Scope

The extension of these features to the other primitive types opens up a number of future possibilities.

One of these would be methods on the other primitive types (and also properties). This could make string and array manipulation more convenient, and additionally provides an opportunity for a fresh start versus the old standard string and array functions, which have notoriously inconsistent naming and parameter orders.

It also means we can easily introduce new superclasses of our other primitive types. For example, a new \Number type superclassing int and float, or a new \Scalar type superclassing everything except objects and arrays.

Proposed Voting Choices

This is a major language change, so it would require a 2/3 majority.

It would be a Yes/No vote on whether to accept the RFC.

Patches and Tests

There is no interpreter patch at present. FIXME.

There is no language specification patch at present. FIXME

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged to
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature
  4. a link to the language specification section (if any)

References

FIXME

Rejected Features

None yet.

rfc/class-like_primitive_types.1482080729.txt.gz · Last modified: 2017/09/22 13:28 (external edit)