I don't like what PHP turns into





And I already know what you will say, looking at the title of the article:

- Who are you? Why do you allow yourself to say that?



I will answer right away so that there are no omissions:



  • I have been professionally programming in PHP since 2004, that is, for 16 years at the time of this writing, and I continue to do this every day.
  • I have been teaching programming, including PHP, for about 10 years and during this time I have released several thousand students
  • I have always been delighted with each new version of PHP that came out from the time of 5.0 to 7.4 and have always been an adherent of the approach "write on the latest version, test on the next"


And yet, despite all the above, I don't like what PHP is turning into now and what it will turn into soon, literally this fall.



Almost every RFC adopted in PHP 8 causes me pain and bewilderment. And I am ready to explain and defend my position.



Basic language concepts change



How does learning a new language usually start? Values, expressions, variables and functions. Likewise, learning PHP is the natural order.



When we start to go through functions, I draw special attention of students to the fact that in PHP the context of functions is closed, "sealed". This is very simple and completely logical - you just need to clearly remember what names the function sees: its arguments and its internal variables.



When we get to the basics of OOP and learn about the concept of "method", we rely on the concept of a function, and add one more item to the context: $ this in dynamic methods. Is something else changing? No. The functions are still closed, their context ceases to exist after the call, nothing flows into the function from the outside, and nothing flows out of it either.



We come to anonymous functions - and here the rules of the game do not change either. Arguments? Yes. Internal variables? Yes. $ this? OK, let's get around this question, otherwise we'll have to discuss a strange thing called "static anonymous function" :)



Next, we add the concept of "closure". Everything is logical with him, too, a separate keyword, a final list of variables from the creation context, the basic principles are not violated. And given that the value is closed, and not the name, then everything is fine in general - the functions continue to be "sealed". Nothing from the outside will seep, nothing will pour out.



Do you know what happens next?



And then we have arrow functions. And it breaks everything.



I am forced to explain that arrow functions violate hard-to-learn principles because they lock in the ENTIRE context at the moment of their creation.



Ops.



But what about the principle of "tightness"? But in any way, they did not give a damn about it for the sake of simplification of writing, saving 6 characters - now we have "fn" instead of "function".



Bad. Inconsistent.



Do you think this is the only example? No matter how it is.



Ask any noob a question - what character do names begin with in PHP? That's right, with the "$"



  • variable names
  • object property names
  • class property names
  • argument names
  • even "variable variables" are also "$"!


Is it logical? Yes. Consistently? Yes. You just need to remember about the constants that don't need $.



What do we have now? Named arguments: wiki.php.net/rfc/named_params



array_fill(value: 50, num: 100, start_index: 0);


Where is the "dollar"? No.



This is problem.



Now you have to remember that you need to write "dollar" in the signature of the function, but not when called. And this is a very serious problem that violates the integral system of the language. This is bad and inconsistent.



For what? Yes, just because someone wanted to transfer sugar from Python to PHP without thinking. However, Python at least uses the same "=" symbol to match name and value, both in the assignment and in the named arguments, and now we will have two of them - the usual "=" and ":" in the new construction.



Almost every RFC discussed for PHP 8 carries the same problem - a violation of the previously established language system. And that's bad. It breaks the mind both for those who have been writing in PHP for a long time, and for those who are just starting to learn it.



See: (wiki.php.net/rfc/match_expression_v2 )



echo match (1) {
    0 => 'Foo',
    1 => 'Bar',
    2 => 'Baz',
};


these are new match-expressions. Can you explain why they use the "=>" symbol and not the usual switch-case ":"? I can not either.



This is again a violation of an already established system. The "=>" symbol has always (before the damn arrow functions, they again!) Denoted the separator of a key-value pair. It now also denotes the argument-return-value separator in the "arrow" and the select-value character in the match statement.



This is bad. This is very bad. This is highly inconsistent. This is even worse than the static keyword, which has at least three fundamentally different meanings.



Natural language unreadability



Show the native English text



SELECT * 
FROM users
WHERE age>=18 AND name LIKE 'J%'


and he, if his IQ exceeds 60, will easily explain what this text is about and what will be done when implementing this text as a program.



Show a genius not familiar with JS the text



const f = () => 42;


and he will not understand anything. Constant? f are these parentheses? Are the parentheses going to a number? What is it?



I've always been glad PHP is far from sacrificing code readability for the sake of brevity. I was glad that it was far from JS, where the principle of code readability was abandoned in favor of "write fewer characters, no one will read this code anyway."



Now I realized that PHP 8 would break the principle of natural readability. And, apparently, irrevocably.



Just look at these examples:



wiki.php.net/rfc/constructor_promotion



class Point {
    public function __construct(
        public float $x = 0.0,
        public float $y = 0.0,
        public float $z = 0.0,
    ) {}
}


Now, instead of constructor arguments, we immediately declare properties and set their values ​​from the arguments.



Guess what is after the "=" signs? Initial property values? Or the default values ​​of the constructor arguments? It is impossible to guess. Find out by reading the code - too. This is bad. Another place to learn by heart.



wiki.php.net/rfc/property_write_visibility



class User {
    public:private int $id;
    public:protected string $name;
}


Public-private property? Seriously? How to understand from this code that we are talking about a readable property and a writeable property?



wiki.php.net/rfc/conditional_break_continue_return



    function divide($dividend, $divisor = null) {
        return if ($divisor === null || $divisor === 0): 0; 
        return $dividend / $divisor;
    } 


Seriously, does anyone need this? Someone wrote for years in PHP and suffered from not being able to write "return ... if" instead of "if ... return"? Do we really need a new yoda syntax for the banal if and return?



Too many ways to do the same thing



PHP has always violated the famous principle of "there must be one and only one way ..." But it did it intelligently, little by little, and reasonably.



Now this principle has been trampled and destroyed. Every RFC that is accepted says, "let's add another way to write if, because I've seen this in Perl / Python / Ruby / Brainfuck!" - and other justifications, except as "I saw" in general, is not given.



What happened:



if ($y == 0)
  return 0;

if ($y == 0) {
  return 0;
}

if ($y == 0):
  return 0;
endif;


- as many as three ways to record the same thing. Not very good, I have to explain: why there are three of them, why it is not worth writing code without operator brackets, and why an alternative syntax is needed.



But this is not enough! Wait a little longer and you will see:



//  -If
return if ($y == 0): 0;


This is how the functions were called:



foo(bar($baz));


You will soon see this:



$baz |> 'bar' |> 'foo'


- brilliant, isn't it? It is immediately clear that this is a function call!



And I haven't written anything about arrow functions yet :)



More, more ways to do what was done before without any problems:



  • match-expressions
  • operator "? ->"
  • two different syntaxes for closure
  • loop + else
  • static constructors
  • property declarations in constructor arguments (!)


and much more, which will only make the code harder to read and the language harder to learn.



Outcome



PHP is evolving. This is an important process that affects a huge number of people and affects the entire programming community.



However, the feeling begins to emerge that development is going somewhere wrong. I am afraid that the adopted changes will lead the language to the fact that programs in it will become increasingly short and less readable, to the fact that it will provide more and more opportunities to do the same thing in different ways, and to learn all these methods will it takes more and more time.



I don't want to see a new Perl in place of PHP in a year. And you?



All Articles