Hi Michael,

On 02/01/2018 10:35, Michael Morris wrote:
I would like to propose a clean way to add some strong typing to PHP in a
manner that is almost fully backward compatible (there is a behavior change
with PHP 7 type declarations). As I don't have access to the add RFC's to
the wiki I'll place this here.

Thanks for putting this together. Perhaps unlike Andreas, I think it is good to look at typing changes as a unified framework, rather than considering "typed properties", "typed variables", etc, as separate concerns. If we don't, there is a real risk we'll end up making decisions now that hobble us for future changes, or over-complicating things in one area because we're not yet ready to make changes in another.

My own thoughts on the subject from a while ago are here: http://rwec.co.uk/q/php-type-system In that post, I borrowed the term "container" from Perl6 for the conceptual thing that type constraints are stored against; in PHP's case, this would include variables, object properties, class static properties, function parameters, and return values. I think a good plan for introducing typing is one that considers all of these as equals.

The biggest issue with any proposal, though, is going to be performance. I don't think this is an incidental detail to be dealt with later, it is a fundamental issue with the way type hints in PHP have evolved. PHP is extremely unusual, if not unique, in exclusively enforcing type constraints at runtime. Other languages with "gradual typing" such as Python, Hack, and Dart, use the annotations only in separate static analysers and/or when a runtime debug flag is set (similar to enabling assertions).

Extending that to all containers means every assignment operation would effectively need to check the value on the right-hand-side against the constraint on the left-hand-side. Some of those checks are non-trivial, e.g. class/interface constraints, callable; or in future maybe "array of Foo", "Foo | Bar | int", "Foo & Bar", etc. There are ways to ease this a bit, like passing around a cache of type constraints a value has passed, but I think we should consider whether the "always-on runtime assertions" model is the one we want in the long term.

If the type is omitted, scalar is assumed.

As Andreas pointed out, you mean "mixed" here (accepts any value), rather than "scalar" (accepts int, string, float, and bool).

The variables created by this pattern auto cast anything assigned to them
without pitching an error.

My initial thought was that this makes the assignment operator a bit too magic for my taste. It's conceptually similar to the "weak mode" for scalar type hints (and could perhaps use the same setting), but those feel less magic because they happen at a clear scope boundary, and the cast only happens once. But on reflection, the consistency makes sense, and assigning to an object property defined by another library is similar to calling a method defined by another library, so the separation of caller and callee has similar justification.

PHP 7 introduced type declarations.

This is incorrect, and leads you to a false conclusion. PHP 7 introduced *scalar* type declarations, which extended an existing system which had been there for years, supporting classes, interfaces, the generic "array" constraint, and later pseudo-types like "callable".

I don't think it's tenable to change the meaning of this syntax, but it would certainly be possible to bikeshed some modifier to simultaneously declare "check type on function call, and declare corresponding local variable as fixed type".



QUESTION: How do we handle the second auto casting case? $a is not allowed
to not be a SomeClass() object, but there are no casting rules.

There are actually more than just object and scalar type hints - "callable" is a particularly complex check - but currently they all just act as assertions, so it would be perfectly consistent for "locking" to also only have the one mode.

When a strongly typed variable (autocasting or not) is compared to a scalar
variable only the scalar switches types. The strict comparison operator is
allowed though it only blocks the movement of the scalar.

Comparisons between strongly typed variables are always strict and a
TypeError results if their types don't match. This actually provides a way
to force the greater than, lesser than, and spaceship operation to be

I like this idea. The over-eager coercion in comparisons is a common criticism of PHP.

In general I really like the outline of this; there's a lot of details to work out, but we have to start somewhere.


Rowan Collins

PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to