📜 ⬆️ ⬇️

Advantages and fatal flaws in php typing

The php language is often abused, usually unreasonably. Particularly surprised that javascript is scolded less. Often this is done by people who wrote on it 10+ years ago, when the language was really damn bad, and the developers in those days did not think about the quality of the code. Look at least at the wordpress code that still causes shock.


They scold unreasonably, but of course there are problems with the language, and they are serious. Understand, if you compare the latest releases of php7 (with a normal OOP and strict typhingting) and php4, the difference will be enormous. However, in the latest versions of the language is not all smooth, and to java / c # so far very far. Moreover, I undertake to assert that the future of php is also rather doubtful (in terms of types).


In other words, let's consider in detail what is good and what is bad in php in terms of typing.


Type hintings


To begin with, let's see why we need phishing in php in general, so that no one has any questions a la "why this extra writings."


Let's digress a bit and see a piece of javascript code:


function filterUsersByAge(users, age) { //  -  } 

What can we say about this feature? She takes some users and filters them by age. But this is not enough, because the questions immediately arise:


What is users? An array? Or some tricky collection object?
Is the age given as an integer or maybe fractional?
Can age be null?
Does this function return a value, or does the passed array of users change?


To understand all this, you need to read the function code, as well as calls to this function. Errors will be difficult to catch, because the language will not swear at any arguments, but will try to somehow bring them to the desired type.


As you know, a programmer spends more time reading and understanding the code than writing a new one, so the lack of prompts in the code is an inhibiting factor.


For comparison, the code on the latest versions of php:


 function filterUsersByAge(array $users, ?int $age) : array { // ... } 

Here we see that the input array of users, the age can be null, also returns an array. Much clearer, isn't it? If we specify declare(strict_types=1) places declare(strict_types=1) , then when we try to shove a fractional number as an age, we get an error.


It seems everything is super, but there are nuances.


No generics


We are looking at this php-function filterUsersByAge and do not immediately understand what array we have come from. What exactly is the array? In java, we could write a List<User> , and we would understand that a list of User objects has come to us. Or Set<User> , and we would immediately see that this is a list without repetitions, i.e. only different objects. (Generally, array in php is a weird mixture of an array and a HashMap, but this is a topic for a separate article)


No qualification for callable type.


Here is an example of the function:


 function reduce ( array $array, callable $callback ) 

What is the function of the second argument? What should be in it?


Only in the comments to the code can we understand that there should be, for example, two arguments. By the way, there are four types of lies: lies, blatant lies, statistics and code comments.


In some languages, for example in TypeScript, you can write directly in the function declaration:


 function fn(action: (a: string, b: number) => void) 

Those. here, as an argument, there must be a function with two arguments (a string and a number), which returns nothing. Everything is as clear as possible, the IDE and the compiler will immediately say if the argument was some kind of not


The strangeness of typhingting and the type of return in conjunction with inheritance


 <?php interface Entity {} class User implements Entity {} abstract class Repository { abstract public function findById(): Entity; } class UserRepository extends Repository { function findById(): User { return new User(); } } 

Here we get the error that findById is not compatible with findById from an abstract class.


The same example in java compiles normally:


 interface Entity {} class User implements Entity {}; abstract class Repository { abstract public Entity findById(); } class UserRepository extends Repository { public User findById(){ return new User(); } } 

in TypeScript you can also:


 interface Entity {} class User implements Entity {} abstract class Repository { public abstract findById(): Entity; } class UserRepository extends Repository { public findById(): User{ return new User(); } } 

On this matter from time to time there are bug reports, maybe it will be fixed someday:



Fatal problem


The biggest problem is that php checks types at runtime, not at compile time. Because, despite strict_types and type hintings, it is a SUDDENLY not strongly typed language.


Two conclusions follow from here:


1) The more checks in runtime, the more brakes. Therefore, too complex checks hardly ever appear. Layered generics and callable with callable arguments will simply put runtime. Runtime typing for class members and in other places will also slow down.


2) Errors are detected only during startup. Those. there will always be situations when, in a tricky situation, the user will do something that is not provided for by tests, and everything will fall


Instead of conclusions


Although (from the point of view of types and OOP) in my opinion, php is a cut above javascript and is suitable for writing complex programs, but of course it does not reach java / c # / typescript, and it is unlikely to ever reach ( see "Fatal problem"). I repeat, it does not reach exactly from the point of view of the type system, in other things, preferences in one direction or another are possible.


Therefore, in a truly complex applications, it is necessary to test everything. It is also possible that phpdoc will add support for complex callable with parameters, and IDE will learn to understand them .


')

Source: https://habr.com/ru/post/346914/


All Articles