
Everything you need (and don't need) to know about PHP's type system - nawarian
https://thephp.website/en/issue/php-type-system/
======
osrec
It actually makes me really happy to see more positive comments on a thread
about PHP. It is an incredible workhorse, and doesn't get the credit it
deserves.

I'm often amused by developers that revile PHP, while going on to use another
language, which suffers from a similar set of problems to PHP, oftentimes with
poorer performance and more complex toolchains.

PHP deserves a little more love, imo.

~~~
bsdubernerd
I always used and use PHP because it gets the s$$$ done.

But truth be told, the hate is deserved. It never was a particularly efficient
language, which might not matter that much, but it _was_ riddled with gotchas,
warts and horrible solutions to many technical and _social_ problems.

Today PHP is faster than many alternatives, many of its warts got fixed, but I
cannot brush off the fact that it's still based on a poorly-designed base and
runtime library.

I'm still using PHP when it makes sense, in the same way I'm still using perl
where it makes sense.

~~~
kyriakos
I agree with both statements, it gets shit done but has its rough edges. Its
improving though and I doubt there's a perfect programming language out there.
At the end of the day what matters are results and how quickly you went from
idea to production and PHP is one of the good ones for that matter.

~~~
87zuhjkas
I think "rough edges" is an understatement. It has serious design flaws and
inconsistencies which are probably never going to be fixed due to backwards
compatibility. It's like C++ now, tons of language features are added over the
years but non of them is able to repair the language, similar to a game of
Jenga, the tower will collapse eventually.

------
paledot
> Important to notice that casting an array with numeric keys into an object
> is valid, but one can't dereference its value because property names may not
> start with numbers.

Not true, actually. The (admittedly obscure) syntax to access a property
beginning with a numeral is `$obj->{0}`. Usually when this happens it's
because someone was trying to be clever with JSON.

~~~
flir
There's another way to get a variable starting with a numeral - abusing
extract(), I think.

~~~
paledot
I've seen a few workarounds, each worse than the last, including casting back
to array, round-tripping through JSON with the array flag set, and reflection.
Hence the public service announcement that this is perfectly doable with the
correct syntax.

------
duskwuff
Adding a static analyzer (like Psalm [1]) to the mixture makes PHP's types
_much_ more powerful. Psalm can use docblock annotations to attach more
complex types to functions and variables, including:

* A "list" type representing a non-associative array

* Types representing specific kinds of values, like numeric-string or non-empty-array, as well as exact values as types (like true and false, or string constants).

* Typing on keys and values in arrays, e.g. array<class-string,int> for an array with class names as keys and integers as values

* Complex typing on the contents of associative arrays, e.g. array{foo:int, bar:string}

* Templated types on functions, like a function which returns an instance of a class whose name is passed in as a string:
    
    
        /**
         * @template T
         * @param T::class $class_name
         * @return T
         */
    

[1]: [https://psalm.dev/](https://psalm.dev/)

~~~
mhitza
Psalm is nice, however I would suggest PHPStan as an alternative for people
that encounter a lot of friction with Psalm.

For example, in a project using doctrine I have to add a bunch of is
null/@psal-mutation-free annotations. As all the methods can return null.

However, if Psalm had support for something like phantom types, maybe I could
tag entities returned from the database for whom certain fields are guaranteed
to have values.

~~~
slifin
Adding Phan to this conversation initially created by the creator of a PHP,
now in the hands of TysonAndre who does an insane amount of good work on it

~~~
noir_lord
For users of the intellij family (idea or phpstorm).

[https://plugins.jetbrains.com/plugin/10215-php-
inspections-e...](https://plugins.jetbrains.com/plugin/10215-php-inspections-
ea-ultimate-) is amazing and well worth the price.

It has a free variant which is still amazing but lacks all the inspections of
the paid variant.

[https://plugins.jetbrains.com/plugin/7622-php-inspections-
ea...](https://plugins.jetbrains.com/plugin/7622-php-inspections-ea-extended-)

------
chx
Minor nits:

1\. "they all inherit from stdClass" \-- this is simply not true

2\. callables should've mentioned anonymous functions

3\. a special typed value can't be casted to anything. -- this is not true,
NULLs can be casted to anything (it becomes 0, "", array() ) and even
resources can be casted to anything with dubious utility value.

4\. casting should mention the intval() , strval() , doubleval() functions

5\. php does not support explicit type definition in variable declaration --
PHP 7.4 however supports typed properties.
[https://wiki.php.net/rfc/typed_properties_v2](https://wiki.php.net/rfc/typed_properties_v2)

~~~
nawarian
I'll definitely edit the post adding the relevant bits you mentioned.

Two special notes:

About 1. stdClass, you're right and I don't know why I just took it for
granted without even testing. My Bad.

About 3. casting special types, you're right again. I didn't phrase it
properly. Casting null to other types won't yield errors and casting resources
too. Their values are normally nothing we should rely on, but doesn't mean one
"can't" perform such casts.

Thanks a lot for your comments, they are incredibly helpful! Cheers!

------
gwillz
This is quite complete, definitely bookmarking for reference.

I've been knee deep in PHP for the last 6 months after keeping it at arm's
length for probably 10 years. It's really quite incredible how much it's
improved and I think the type system is the major factor for me. It's not
perfect but damn - I can get some stuff done really quick now.

~~~
gwillz
I'll add though; the real benefit only comes with heavy use of objects, like
in Yii/Craft. If you've got keyed arrays everywhere it's still a hellhole.

~~~
DJBunnies
Arrays can become collections.

------
jonny383
PHP rocks in 2020. Couple it with laravel or something and you get a solid
platform to build a monolith-type web app with really fast performance.

~~~
bnt
Isn’t Laravel the worst performing framework out there right now, like even
Rails looks like a viable option in terms of speed?

~~~
jonny383
Ruby is slower than PHP7+ by orders of magnitude. I doubt it.

~~~
amval
Orders of magnitude? Do you thibk that PHP is at least x100 times faster than
Ruby?

~~~
jonny383
Alright, maybe an exaggeration. But the difference is huge.
[https://benchmarksgame-
team.pages.debian.net/benchmarksgame/...](https://benchmarksgame-
team.pages.debian.net/benchmarksgame/fastest/php-yarv.html)

~~~
tutfbhuf
Well that is a benchmark with a set of specific mathematical problems like
calculating pi digits. I would rather compare Rails with Laravel e.g. in terms
of requests per second or speed of json deserialization. See
[https://www.techempower.com/benchmarks/](https://www.techempower.com/benchmarks/)
Symfony, Lumen and Rails seems to be somewhat equal in performance, but
Laravel is a bit slower in respect to the benchmarked web related criterions.

------
untog
I have to say I’m impressed by how far PHP has come. I haven’t written any in
years (well over a decade, even) but the commitment to improving a language
many have written off as a dead end is laudable.

------
forgotmypw17
While we are on the subject, does anyone know of a way of having required
variable declarations in PHP, similar to the way Perl's "use strict" works?

This is one of my most common sources of bugs, and it is frustrating not
having this be available, when it makes my life so much easier in Perl.

Lately I've been thinking about doing something crazy like implementing my own
variable system...

~~~
notRobot
> Strict typing mode. In PHP the declare(strict_types = 1); directive enables
> strict mode. In strict mode, only a variable of exact type of the “type
> declaration” will be accepted, or a TypeError will be thrown. The only
> exception to this rule is that an integer may be given to a function
> expecting a float.

[https://www.brainbell.com/php/strict-
type.html](https://www.brainbell.com/php/strict-type.html)

~~~
paledot
Worth emphasizing that this directive applies per file, and affects functions
_called_ (not those defined) in that file. Not sure if there's a mechanical
reason for that, but if I'm writing a new class I'd like some assurances that
it's being used correctly. If I could enforce strict types on _calling_ code,
I could do away with a certain class of validation.

~~~
zerocrates
The point is supposed to be that once you write in a scalar typehint for a
parameter, you don't need to do validation for it being the right type within
the function: even if it's called from a non-strict context, that just means
PHP will cast it before passing it. So you can avoid type checking code in
your function but consumers can still use the more traditional and dynamic
style of PHP if they want to.

I can't quite think of the type of validation you'd be able to avoid with the
sort of "inverted" strictness you're describing.

Certainly I can think of issues people could have if not using strict types
(basically, unexpected casts), but not things that you could actually validate
from within the function.

~~~
paledot
Good point. My method may behave unexpectedly if you call `sum(true, false)`,
but it's not identifiably different than `sum(1, 0)`. Sorry, it was late, and
I failed to mention my actual use case: I work on a legacy application and
want to enforce correctness on the new code I write. I'd rather write a new
module and enforce that the calling code in the legacy app is using it
correctly, than try to add strict types to the legacy classes.

------
aslamc
Is there a good reason to still use php when you can use hacklang
([https://hacklang.org/](https://hacklang.org/)) which has much stronger type
system. Some would even call it php++.

~~~
simonhamp
A lot of what Hack introduced to the PHP community has become available in
suitably forward-thinking ways to allow for a sensible amount of backwards
compatibility and are opt-in.

For example, you can set strict typing on a per-file basis.

`declare(strict_types=1);`

I believe that the performance difference between the two is negligible now
too. So it really just comes down to personal preference/platform legacy.

But Hack is on a different path which is potentially going to make it harder
to share code between PHP and Hack.

PHP still has by far the larger community.

Given the choice today, I’d run with PHP.

~~~
asddubs
the only thing that sucks about strict typing is that there's no way to toggle
it globally. so if you want to transition a codebase that's simultaneously
actively being developed in other ways, you have to mess around with scripts
that append it to the start of all php files/remove it again

~~~
nawarian
Nothing that tools like Rector can't help you with.

I believe this extra step is incredibly important, given most of your
dependencies you won't control and forcing strict types to them is not very
clever IMO.

~~~
asddubs
I guess it wouldn't work if your dependencies weren't easily seperable from
the rest of the code. in this case there are no dependencies, it's all custom
cobbled together, for better or worse

------
choma
Completely unrelated but, if the site owners read this: pleas, make the CSS
::selection a different color from the background, please!!

~~~
nawarian
Thanks for pointing this out. It annoyed me a lot as well. The whole "dark
mode" css was a "better than nothing" thing, and now I'm collecting the "must
fix" things. This is definitely on the list!

That said: the website is open source, feel free to submit a PR if you find
time before I do :D

------
wolco
Main takeaway: strict types won't make your code faster!

It may make it slightly slower

~~~
fennecfoxen
The point of strict types is generally not speed, but rather, to make your
code more correct.

~~~
chiefalchemist
Correct? I'd probably say predictable.

~~~
fennecfoxen
Eh. If MyPy complains that I'm passing an `Optional[Entity]` into a method
where only an `Entity` can go, it's just helped me avoid a runtime error when
I try to get `entity.name`. Not sure what the exact PHP equivalent is, but
there's all sorts of bugs you can easily introduce if you're not careful with
types.

~~~
wolco
PHP doesn't compile so all errors become runtime errors.

~~~
nawarian
Small correction: php IS compiled, just not the way we're used with the term.
See
[https://thephp.website/en/issue/php-8-jit/](https://thephp.website/en/issue/php-8-jit/)
for more information.

The answers below show a good solution for this issue: use static analysis
tools in build time and potentially even as a pre-commit hook.

