Hacker News new | past | comments | ask | show | jobs | submit login
What's new in PHP 8? (stitcher.io)
214 points by maydemir on Aug 13, 2020 | hide | past | favorite | 168 comments



You know, I used PHP back in the early 2000s and sometimes I miss it after having worked with Python, Ruby and Elixir over the years but it's not necessarily related to the language itself.

I use this one program called Sendy (a PHP app) to help manage my email list. It's a typical LAMP set up.

It's been running on a $5 / month server uninterrupted for 905 days with no down time related to the app malfunctioning. The whole system uses around 300mb of memory.

Yesterday I decided to spin up a new server to finally retire the old one since it was using Debian Jessie that just went EOL 2 weeks ago. This required migrating a ~3 year old version of Sendy to the newest one (dozens of database schema changes included) and export / import my entire database.

Everything just worked and all I had to do was rsync the PHP files to a directory and access the site in a browser, and it was upgraded and ready to go.

I even ran into what I thought was a bug because my existing forms weren't working, so I looked into the single PHP file that was the form's action and within 5 minutes determined I was missing a hidden field (something Sendy added in a recent version). That was the first time I ever looked at its source code and PHP in a long time.

It very much reminded me of my PHP cowboy days. No complicated build process, no dependencies (the whole app uses PHP's standard library), no having to restart the server between deploys, etc.. I know there's downsides to that and I'm very aware of them, but after having worked with increasing complexity for the last 10 years of web dev, man it felt nice for a change.


Sendy is without a doubt one of the worst written pieces of software I’ve ever had the displeasure of (a) supporting in product And (b) having to patch.

I would quit working in software dev and become a fucking gardener before I would work on Wordpress projects all the time, and Sendy makes Wordpress look well written.

Edit: cowboy is a very apt term for Sendy. If the cowboy were drunk, and tried to make babies with the cows.


"Sendy is without a doubt one of the worst written pieces of software I’ve ever had the displeasure of (a) supporting in product And (b) having to patch."

So you're saying you've never worked with Magento?


My thoughts exactly. Sometimes I think I hate Magento for being so overly complex, slow, resource-intensive, and feature-poor yet bloat-rich that only Adobe could be interested in it. Then I think of the poor people paying me to maintain and write extensions for it.


Does magento have any kind of code reuse, at all? Does it use classes to encapsulate logic and data? Does it use any kind of separation of logic and display?

If it has any one of those things it’s already better than Sendy. Sendy literally (and I mean literally not figuratively) looks like someone used stack overflow and copy/paste instead of any kind of education or experience writing code.


I didn't carefully analyze the code base but in my mind it's a victory if I can skim code in an unfamiliar code base / language and within a couple of minutes figure out a problem (not a problem with the code, but how I was using it).

Did you run into bugs with it that required patching? I haven't to my knowledge.


It doesn’t support (and yes I asked the author, he refused to add support) tls connections to the database (despite that being a ~2 line change when the dB handle is opened) - because the code is a metric fuck ton of copy pasted code (ie the same exact code copy and pasted in dozens of files) patching it to support tls means we have a non trivial system in place to patch the code.

It also tries to use a MySQL database as a queue/cache which is (predictably) terrible at larger volumes when you have eg a db cluster tuned for durability rather than raw throughput.


Can you elaborate on what makes it that bad? Some snippets of code, or egregious bug reports to satisfy my curiosity. Otherwise, it feels like bad-mouthing software.


For example the db connection logic is about a dozen or so lines. Those same lines are copy pasted into dozens and dozens of files. The same goes for other logic.

Want to fix a piece of logic (ie add tls support to the db connection)? Well you have a couple of dozen files to make the same change in.

And no i can’t link to it because it’s proprietary, and the really ridiculously bad code is even “obfuscated”, in a manner.


As someone who wrote their last lines oh PHP in something like PHP 5, this list tickles my desire to take PHP for a spin again. Not only does the language appear to be much improved, but also the frameworks look so appealing! I'm seriously over dealing with all the low-level plumbing that comes with building Node/REST SPAs just for what's essentially a bunch of forms.


Laravel is a great framework to work with, I would seriously recommend giving it a try.

As for NPM and the JavaScript packages, this is a flipping nightmare and I hate working with it!


I hate to state the obvious, but it's the matter of familiarity.

I've been working almost exclusively with javascript and typescript for the last 4-5 years; so that now, while trying to write an amateurish Symfony project (because shared hosting) and appreciating the maturity of Symfony, I still hate almost every moment of it and hope I could have used typescript.

Anyway, what's wrong with npm and how is it so different than composer?


One that I can think of:

The way npm install always check latest package version and use them, even if package lock already exists. Which broke apps build many many times due to developer does not recognize this behavior. I know there are npm shrinkwrap and npm ci. Its just other package manager usually follow lockfile on install and have other command to upgrade the lockfile.

Also npm install download gazilion file for each dependencies. With deep directories.

In the past, there are problem because npm way of installing dependencies and hitting this infamous windows file path length limitation.

All are now already fixed or have alternative. But at that time, composer definitely much simpler and reliable.


If you need APIs (REST or GraphQL) take a look on Symfony / API Platform https://api-platform.com/


That looks amazing. I'm going to be busy exploring its possibilities for the next few days.


Data classes, attributes, matching expression, all excellent changes. Just missing async/await syntax to defer io bound tasks.


"This RFC fixes the very strange case in PHP where 0 == "foo" results in true. There are some other edge cases like that one, and this RFC fixes them."

It's good they fixed it I suppose, but yikes. As much as people say PHP has advanced from its fractal of awfulness days, a lot of those fixes are shocking if you come from other languages.


Most (non-strongly-typed?) languages have weird edge cases of this sort. There's a very funny presentation by Gary Bernhard highlighting some of these for Ruby/Javascript: https://www.destroyallsoftware.com/talks/wat

If you look hard enough, you'll probably find some site that shows surprising behaviors of your favorite language. Examples:

Python: https://github.com/cosmologicon/pywat

Javascript: https://loomcom.com/blog/0097_the_wats_of_javascript.html

Ruby: https://idiosyncratic-ruby.com/29-limitations-of-language.ht...


The issue is coercion sanity - not that PHP or JS are sane by any other standard to begin with. You can do `0 == "0"` in Javascript (try it now in the devtools console) and it'll coerce the right hand based on the left hand using parseInt/parseFloat, just like PHP. What it won't do is parse the string "foo" as a zero, which is insane even by Javascript standards.

`parseFloat("foo") == parseFloat("foo")` and `parseInt("foo") == parseInt("foo")` in Javascript evaluate to false which is the sane thing to do. `NaN != NaN` is part of the IEEE 754 floating point standard, which predates every single one of the languages you mentioned.

We're all competing in the olympics of suffering, so none of us should be promoting this shit :)


It's important to note here that PHP is converting to an integer, while JS is converting to a double. Integers don't have NaN as a concept. JS doesn't have integers, but if it did it would probably make the same kind of mistake. (This is a guess of course, but a reasonable one given the other insane conversions it does.)


Python may have Wats, but C has Nasal Demons.

https://en.m.wikipedia.org/wiki/Undefined_behavior#Examples_...


Java:

    jshell> Long a = 12l; Long b = 12l;
    a ==> 12
    b ==> 12
    jshell> a == b
    $3 ==> true
    jshell> a = 54321l; b = 54321l;
    a ==> 54321
    b ==> 54321
    jshell> a == b
    $6 ==> false
¯\_(ツ)_/¯


Really? Not being a Java guy, what is the explanation for this?

Terms like boxing and reference comparison come to mind but I can't stitch them into a narrative to explain this.


`Long` is a boxed (reference) type, but small numbers are interned so you get the same reference when boxing a primitive value. Larger numbers aren't interned, so you get fresh boxes.

https://stackoverflow.com/questions/1700081/why-is-128-128-f...


Reference comparison it is with a twist: the jvm caches the most common integers. You'll get the same object from -128 to +127 when implicitly assigning value. This is part of the spec, and can be set to a larger pool with -XX:AutoBoxCacheMax (but cannot be turned off).

If you explicitly ask for a new object (Long a = new Long(123l);) you will get a new object and the comparison will fail as expected.

The moral of the story is to always use .equals().


I love the "Wat" talk. I wrote a blog a few years ago where I attempted to dig into the JavaScript cases Gary's cites and figure out what is actually happening.

https://medium.com/@mikehall314/wat-s-happening-a-closer-loo...



Are there real use cases for type coercion?


For example, it is helpful to avoid having to do tons of explicit integer parsing when working with the DOM, which uses strings for everything


Yes. You have a list of floats and you want to add n to the n-th element. Then n is both an integer (when indexing the list) and a float (when adding).

Of course the language can require an explicit cast, but in most cases it goes against the intuitiveness and simplicity that dynamic languages want to achieve.


And? None of it should be condoned. It's all bad. How is that any argument?


I think it is good and should be condoned. Sometimes having simple rules with the occasionally strange outcome is better than having a complicated set of rules to achieve a simple set of outcomes.


It's a good thing all other languages are perfect and have always been perfect, otherwise the rest of the community would have no pedestal to stand upon.


Nobody is saying other languages are perfect. These are particularly egregious mistakes though.


It was a consequence of type conversion in a loosely typed language. There are consequences to loose typing, one of them is edge cases. PHP also has strict typing capabilities. If you need strict typing, then use it, it's right there for you.

My criticism isn't the valid criticisms of PHP, it's that no matter how much progress the language makes people are quick to find reasons to be dismissive.

The language is good, people do good work with it. Lots of good work. How Javascript became the golden child in a community that can't forgive PHP is beyond me.


> My criticism isn't the valid criticisms of PHP, it's that no matter how much progress the language makes people are quick to find reasons to be dismissive.

It's perfectly valid to be dismissive of PHP and you should recognize that. Main reason: there's a metric ton of PHP 5.X websites out there who are never going to be upgraded. That alone is a reason enough to distrust PHP.

If the community makes a concerted effort to introduce automated upgrades of legacy PHP codebases to the newer (supposedly better) versions then I personally would become a fan.

Everybody can tout the newest and greatest. Working with -- and improving -- the legacy stuff is what earns the respect of many, myself included.

(Disclaimer: not a JS dev. You seem to imply some kind of irony that JS devs mock PHP but this is not the case with me at least.)


Your point of view is so backwards. You dismiss an entire tool because legacy work exists? So because Windows 3.1 doesn't upgrade to Windows 10 I shouldn't bother? Because IE11 doesn't run ES5 we shouldn't work with it?

You are free to criticize the enormous amount of legacy codebases out there, but that is not the fault of PHPs core team and the community working to improve the language and ecosystem, and it doesn't make PHP a bad tool. Environment maintenance isn't the languages responsibility and PHP has been -very- careful with it's upgrade path. It's childs play to move between versions.

If anything you should be impressed at legacy PHPs robustness. How long will modern stacks last unatended? Barely a year in my experience before some CI or dependancy breaks and the whole tower crumbles. Try and run an NPM based build pipeline in two years and tell me how that automated upgrade path worked out.


This analogy doesn't work. You can still use a lot of these legacy mistakes today.


You can write bad code in any language, but we've tried to move on from that and employ solid software engineering within PHP.


> You dismiss an entire tool because legacy work exists? So because Windows 3.1 doesn't upgrade to Windows 10 I shouldn't bother? Because IE11 doesn't run ES5 we shouldn't work with it?

The crucial difference here is that nobody ever will even attempt to upgrade the PHP 5.X websites to PHP 7 or 8, whereas a lot of people gradually upgraded from Win 3.1 to Win10 over the years.

Obviously I am not saying "don't bother". Judging by your strong words (which don't make your argument more compelling) you seem to be a fan so you do you, code all the PHP that you like. I am giving you a realistic take on why many skip PHP. You getting a bit emotional over this doesn't change my stance.


It's just a tired discussion sorry, hence the strong words, I respect your points of view so far and I appreciate the discussion (for what it's worth I've been upvoting your comments as I see they're getting grayed out).

There is a strong, intelligent community backing PHP and working with PHP, and you are dismissing it for things out of their control I feel. You're not taking a realistic perspective on what starting a project with PHP is really like today. It's fast, it has easy deployability, and you can use all the software engineering best practices you so please. Instead you're implying that the abandoned projects from yesteryear are what PHP is about today.

During it's prime, the web exploded with PHP installations built by people who had never touched software before and may never have touched it again, that's what legacy PHP is. It can't be fixed by the PHP community because those installations aren't run by people who are involved in the PHP community. PHP has a very sane upgrade path, but the people who run those installs will never know about it or be interested in it.


I agree that mine -- and many others' -- points of view on PHP are skewed by a sort of a "shameful past". And I agree it's uncharitable. I am facing the same myself in the Elixir community which, despite being a very well-made language with an excellent runtime is still being derided by its lack of strong typing.

So I know your sentiment and I sympathize with it.

I too was a bit too dismissive and I am sorry.

My point was more along the lines of the seeming fact that the PHP community shrunk and, as you said, the original people who made it popular are long gone, likely to never come back. Not sure if anything can be done about it. As a fan of a fringe language I know how it is.

For what it's worth, I only heard good things about Laravel and several other libraries (or frameworks? don't know) along the lines of big productivity boosts.

Here's to hoping that one day all of that will converge somewhere where all of us will have to deal with less BS.


There is such a thing as writing code that is good, functional and satisfies the business requirements; this same code can also run untouched for years. Yes, this is a thing, and actually a hallmark of quality work.


Non-constructive snark with zero correlation to the topic at hand.

I have been visiting -- and repairing -- PHP 5.X websites for years. They are anything but stable. I did maintain Java mastodons for years and they have been both (a) stable and robust and (b) legacy. But PHP projects I was in long time ago -- far from it. Could be anecdotal evidence.

To not make this annoying for future readers: I am okay with legacy code sitting untouched (although I will argue it is usually more broken than you seem to imply), but I am not okay with advertising a language that definitely didn't help the reputation of the IT branch in the eyes of everybody else. PHP sits on a broken foundation.

I have a right to express my opinion and you have a right to express yours. Let's leave it at that since we aren't going to achieve anything here (except flags for non-constructive posts).


Oh please !!


It's not a binary of good/bad, it's how good and how bad? PHP in my mind is quite bad. A lot of other languages still suck, but suck significantly less.


It's a shame PHP borrowed so much from Perl but not separate "eq" and "==" operators that coerce to string and number before comparing. I want always one or always the other, not both unpredictably.


PHP half-copied Perl a lot. Another example is implementing arrays and hashes, but not as separate types. So you have odd behavior like the array sort functions sorting values but not renumbering keys because there's no distinction between an array and a map. Or copying Perl's string interpolation and concatenation operator but not its regular expression literals, so writing regexes in PHP requires an extra layer of escape sequences.


I'm not aware of any extra layer of escape sequences required in PHP compared with Perl. Could you elaborate?


PHP requires escaping quotes and literal backslashes (i.e., backslashes not used for metacharacters or escaping other characters). For many cases, it doesn't affect anything, but it can turn into a bit of a nightmare if you're matching anything involving backslashes since you need four backslashes to match one literal backslash. Perl's regular expression literals are also nicer for things like splitting a long expression over multiple lines.


I thought preg_quote() took care of that just like quotemeta in Perl?


Yeah, that's a real shame. I wrote lots of Perl and while it requires a bit of experience, I almost never incurred in issues such as those we see in PHP and JS. The fact Perl is also quite strict in you specify if the variable is hash, array or scalar also helps a lot, and IMHO the concept that it's the operator, not the operand that determines the type of the arguments is very powerful.


Yes, maybe, but who would write that? Seems an arbitrary example used to denigrate weak typed languages in general. Not sure what is bering tested there, but easy enough to do this: if (is_numeric($foo) and !intval($foo)) {


Should a string, when converted to an integer, become 1, not 0? (Unless it is a string of only digits, like "567". Then it should become 567.)

  (bool) 'x'  //  true
  (int) true  //  1
If a string is truthy in a boolean situation, shouldn't it also be truthy in a numeric one?

The types form a hierarchy in my mind, from simple to complex: from boolean to integer, to float, to string, to compound types like arrays and objects. It seems like values should cast up and down the chain uniformly.


These are easy questions.

1. If you convert a string which has non-numbers to an integer, an error is raised

2. Truthiness should not exist as a concept. Just booleans and expressions that evaluate to booleans.

PHP's backwards compatibilty promise makes these more difficult questions, of course.


> 2. Truthiness should not exist as a concept.

Meh, it's actually quite useful in many situations.


Easy questions but not obvious answers.

What kind of error to raise? Do you return a NaN? Throw an exception? Both have their uses.


Throw a standard exception. E.g. python calls it a ValueError. Returing NaN is clearly wrong design.


In reality, if you know what you are doing, you would never compare like that (0 == "foo"). What would be the use case?

If you on the other hand don't know what you are doing, you are going to shoot yourself in the foot in one way or another.

If you really have some dynamic type situation and you for some legitimate reason don't know if your variable is going to be an int or a string, you would just compare using the === operator, which is a standard and well-known tool and does not have this issue.


I could see this coming up in a pretty straightforward way actually. I used to have a coworker that would always write his conditions backwards, so like

    if(false == something) {}
In this case it's a semi-obscure C programming style to avoid accidentally using = in an if statement. (I think it's silly, but a decent number of people do it). So I could easily see a case in PHP where someone writes...

    if(0 == $foo)
and $foo usually holds a numerical string, but maybe a user entered "" there and now it's cast to 0 and maybe that code path shouldn't be taken.


> What would be the use case?

Reading data from an excel sheet. A1 is “foo”, A2 is blank. B1 is =A1, which evaluates to “foo”, and B2 is =A2, which evaluates to 0. If you want to aggregate according to column B, you have to compare 0 and “foo”.


You have an excel sheet with various unknown data types which can be a string, a number or a formula that needs evaluation? And you don't check types of variables before comparing them? In that case I would argue that you fall into the category "not know what you are doing", because checking the type would be the first needed thing. That is the very first situation in which it is needed in fact...


I think that the big mistake PHP and JS made was to loosely pick their weak typing from Perl while trying to look too much like Java. Perl has different operators for numeric and string equality, so you know that `$a == "3"` would convert both its arguments to number and then compare them, while `$a eq "3"` would convert them both as strings and run a character comparison on them. Using == for both was kind of asking for people to get confused and mess up, IMHO.


I’ve never used Perl but I periodically mistake eq and = in bash scripts. It’s quite annoying since there’s no obvious indication that one is for numbers and one is for strings.


There's no obvious indication what the standard C function

  void (*signal(int sig, void (*func)(int)))(int)
means; if you don't know C it's plain gibberish, impossible to fully understand.

Everything in computers (and I may say, more in general in life) is based on assumptions made on knowledge we implicitly have. After a while, writing eq or == becomes natural and you stop mixing them up. These kinds of errors are frequent when you don't use something daily; for instance, after more than a decade I still keep forgetting Powershell's syntax because I don't use it often and when I do, I tend to do basic things.


Seems like this still doesn't fix the infamous "1E1" == "010", which I guess can't be fixed without breaking a lot of old code and assumptions.


Why does 0 == "foo"?


"foo" is type casted into an int and, since it's not an int even when casted, it gets casted to a falsey 0.

(int)"9" === 9

(int)"a" === 0

I assume this will cause backward incompatibility? I could see people relying on this instead of is_numeric. Not sure I like this change, since it introduces multiple ways of type casting (and therefore complexity). Before, it was obscure but simple, now, it'd be both obscure and not simple.

EDIT: It will cause backward incompatibility https://wiki.php.net/rfc/string_to_number_comparison

I'm surprised this was 44 against 1 in the vote. Seems like it's very likely to cause issues. IMO they should just implement a "strict comparison" mode, where comparing different types throws a runtime exception. Or just deprecate "==" for "===".


>I'm surprised this was 44 against 1 in the vote. Seems like it's very likely to cause issues.

On the other hand, seems very much like the kind of crap that you're better to rip the band-aid and fix, than to keep for an eternity lest the fix causes issues...

>Or just deprecate "==" for "===".

As if this would cause less issues?


> you're better to rip the band-aid

Not for silent failure. This soft of change means that tons of systems will fail in unexpected ways in unexpected places, and often people will never know about it. It's a security nightmare.

Ripping the band-aid off is much more compelling when it will result in an exception. Silent failure, though. Ugh, if you actually care about writing reliable software, it's the worst.


Automatic type conversion is prone to errors. Either they acknowledge that and force strict comparison (or add a way to do that), or they ignore and thus their change has no real effect, since mistakes will still happen with the new scheme.

>As if this would cause less issues?

Causing issues isn't the problem. Transparently breaking code is. Deprecating would give time for people to adapt their code and would warn them about the downsides or loose type conversion. Changing the semantics of loose comparison will make static analysis and finding potential issues way harder (and may post-pone finding the problems it introduces to years down the line). Adding a mode that warns/throws when encountering loose comparison would both make current code still work, and warn users of potential issues.


> I assume this will cause backward incompatibility?

Yes but I assume codes that will be broken by this are already broken.


"If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number"

And a string that doesn't look like a number at all is converted to 0.

No, I'm not condoning this madness.


Well, in C you can cast any random set of bytes to an int, so there's that...


Sure but in C you usually do that explicitly, on purpose. Here it's almost certainly not what you wanted or expected.. Also, C is 20-30 years older and I don't think I've ever read anyone really compliment its type system in any way other than saying it's simple.


If one doesn't know the language, they can write shitty code, regardless whether it's C or PHP. Any decent PHP programmer knows about the `===` operator that doesn't do any type juggling.


This problem isnt really fixed with === per se. Converting strings to numbers is a common need, and the weird type conversation here is broken (and being fixed) for more than just implicit conversions in comparisons.

The PHP team is calling it "saner numeric strings"...seems to indicate they agree.


Should it be shocking? It's another language that has it's own history and culture. It evolved it's own way.


I used to use PHP as a web backend and then moved to Go. Forgetting the debate about the actual languages, it makes so much more sense to me for a web app to be a full-fledged, self-contained program which happens to listen on a network interface and respond when things make HTTP requests at it.

The old-school style, where routes map to scripts or parts of scripts and a separate web server like Apache or Nginx sits in front of the app, feels harder to reason about (does this thing persist across requests?), harder to debug (where did that error message end up?) more brittle (did this fail because of my script or my web server config or something else?) and more dependent on configuration magic (i.e. various text files lying around governing the behaviour of things).

So although some of these changes look cool, I don't think it's the language itself that most needs improving.


Funny. I completely disagree, and actually find it odd someone actually wants desktop style application state on web apps. One of the beauties of the PHP style of app execution is that application state is a lot simpler. Instead of having a running application server-side, which can be in a continuum of states, PHP forces you to start every request with a blank slate. Application state must be explicit (with serialized server-side sessions or browser-stored cookies). This makes it trivial to reproduce requests, trivial to debug, trivial to scale horizontally.

To each his own, I guess. I just find your position genuinely surprising.


By starting every request from a clean slate, you have much less mental overhead (did I accidentally reuse a variable from a previous request?) and it eliminates an entire class of programming bugs. It's the best thing about PHP, and despite this approach PHP still runs faster than many similar languages.


I think the "clean slate" benefit is achievable almost for free in a monolith though - each request is a separate invocation of a handler function which is given the context it needs to run (e.g. an HTTP request, an output stream and user-defined context).

The user-defined context is the only route into the application state and can be as wide or narrow as you need. So you can share persistent state deliberately, e.g. by having that context contain a pointer to a db conn, but this is always a conscious, opt-in choice, and errors like accidental reuse should be impossible unless you're doing something inadvisable like using global variables.


After doing Java Spring I realized that the Java monolith was very leaky and inflexible. That is why you have strong trend of micro services.

In 99.9% of cases in web development you want the PHP model of doing things. The 0.1% case is the asynchronous background job, that can be solved, maybe not as elegant as in other languages, but why optimize the edge case?


My backend is written in php and I simply have a separate container running a copy of the same php codebase that has a long running process pulling from a pubsub queue in a loop.

So anything that needs to be processed asynchronously, like say, sending out a few dozen emails or notifications, I just publish the task to the queue and that other container handles them.

This could be simplified even further if you use a pubsub service that can post data to a url as it comes in. Thus allowing the single php container to asynchronously process the tasks all in their own individual threads.

This didn't work for me as Google cloud's pubsub seems to absolutely flood it's target with requests seemingly ignoring 503 or any other error code and not backing off until it has dos'ed your server.


The problem lies in your last point. Any PHP+Apache app, no matter how bad the programming practices, has the property that every request gets a blank slate except for explicit database connection. In most other stacks it is way too easy to add a singleton class or a global variable and break that guarantee.

That said, I'll gladly take the guarantees of a type checker in exchange for giving up the guarantees of statelessness. It would be nice if there were a stack that could give me both.


I think it comes down to how we assess the cost of things. To me, the issues you identified with state (which I agree are real issues) are straightforward to overcome with disciplined design. On the other hand, I find not having application-wide state to be a handicap - e.g. I might want to have my application process batch jobs asynchronously or share state between requests in a highly efficient (read: in-memory) way.

Of course there are solutions in PHP-land, e.g. "run a job server" or "use Redis", but I find the overall cost of introducing more programs/services/components to be very high, in terms of learning curve, portability, maintenance and debugging.

I've spent the last few years replacing a crumbly, brittle, temperamental PHP/nodejs/Gearman/Redis/Nginx/Supervisor stack with a Go monolith so I'm sure that influences my opinion :-)


Does that mean you had to re-invent the wheel with your go monolith for a lot of things?

My understanding is that the go philosophy is very package independent and the availability of existing code to solve common problems is rather sparse.


Interesting take.

I don't really agree, php routes are handled natively and very simply and easy to reason about using the .php extension.

Its the frameworkers that broke that design with clean urls and fancy complicated routers.

Php behind Apache or nginx is incredibly simple and easy to reason about.

Browser loooks up this file url, this file url runs as a script and its output is returned.

A bug in one file isn't propogated to all others so you can have highly reliable services with only partial failures from time to time.

Whereas a bug in one route of a golang server may take the entire service offline.

I do much prefer the deployment and shipability of a golang service, so much I am willing to give up the simplicity of PHP.


Absolutely, having a service that just listens on port 80 is so much simpler to reason about. I would also add a much easier development setup, as well as deployment to your list of advantages.

That said, having a Go service just be exposed to the wild wild internet may not be a smart idea. Take a look at this issue [1], it is perfectly clear that Go services (relying on net/http) still need babysitting by a competent reverse proxy. It is a case where Go's mantra about simplicity leads to leaky abstractions and just clearly immature solutions.

Also not talking about TLS certs, WAF and other concerns that also may bring nginx etc on board anyhow.

[1] https://github.com/golang/go/issues/16100


Lol I remember seeing this timeout issue years ago and immediately deciding I would never use Go for HTTP (which is what it was designed for). This makes Go vulnerable to numerous slow attacks and there's no way around it besides "use a proxy".

My guess as to why this issue is left open? Google has global timeouts set on all the network edges so they don't want each service to use its own. Whats good for Google overrides whats good for the supposedly open source project.

This is pervasive in most of their projects. Google open source is like the Reapers from Mass Effect series. They leave some crumbs behind to ensure the software ecosystem develops along desired paths. Not out of charity, they do it to ensure a successful harvest.


This timeout issue is indeed baffling. I believe many Go services out there may have set their timeouts to something ridiculous like 3600 or 86400 as a "fix". Hello slow lori.

Another concern is that the lifetime of a PHP app is rather short, measured in milliseconds. This is actually a rather robust approach. Crashes, memory leaks, all sort of weird states are brushed away immediately to be replaced with fresh state for the next request. Apache/nginx is acting as a supervisor and allowing a lot of shit code live out it's days unnoticed.

Contrast that with long-running Golang processes. You won't get away with sloppy code there, raising he bar considerably. Running a Go executable without a monitoring supervisor is sketchy at best.


I'll be honest, I'm pretty anti-Go. Its filled with hacky workarounds for when various things don't fit their "simple" abstractions. File IO and paths is laughably not cross-platform because of this, for example.

Networking is another example. And casting to interface while the built-in collections secretly use generics.

A good way to avoid all these problems is to use a language with great cross-platform support like Java or C#.


Personally I think that separating the application from the web server is good thing, but I do agree that this is the part that can give you the most trouble.

Running a PHP project isn’t as easy as

  git clone
  make run
because of the web server. Difficult to configure, hard to share configurations between machines, differences between operating systems (and Linux distributions) where to put configurations, different ways to hook into php.

Projects starting to rely on specific web server configurations for different application behavior, e.g. htaccess files.

Hard to debug when you need to special request handling like terminating the request but continue executing or continuously stream data (web server response cache).

I guess that is the price you pay for separating the application from the web server.


The old-school style you describe is indeed old-school and was abandoned by most PHP developers ~10 years ago.

Modern PHP projects will have a single entry point that handles all requests, with path-based routing done in code.


in cheap shared hosting apache setups its still the best way to do 7t oldschool. still love it


Shared nothing is a huge benefit in simplicity.

“Does this thing persist across requests” is ridiculously simple to answer in php because the answer is “no, unless you very explicitly told it to”.

In a go or java or whatever service you have to know if your “thing” is specific to the request handler, or if it’s part of shared state.

There is no reason that routing in a php app has to be done via mapping urls to php files, it’s a very common practice to have a front controller that bootstraps the app environment and in turn handles routing of the request to a piece of logic.


I know this replicates the sentiment expressed by other in this thread but still: Go does not do away with the need for front end servers for deployed end products.

And so the eventual proxying Go behind Nginx or Apache comes with it's own cost since Go is nowhere near as tested as PHP when it comes to server integration.


> web app

I think that this vague definition, right here, is the source of disagreement. Are we talking about small blog with comments?

Or are we talking about one of the services of a medium-sized company, that needs to provide a platform-agnostic API, and real-time updates to subscribed clients with websockets?


Yeah, in my case I'm talking about a thing that is largely a web app but also does other things which don't fit well into the one-script-execution-per-request model.

That being said, I would still prefer a monolithic application for a small blog with comments because I think it's easier to manage, deploy, encapsulate, test etc.


> The JIT — just in time — compiler promises significant performance improvements ... There haven't been any accurate benchmarks done at this point, but they sure will come.

They wrote a new compiler, for performance reasons, and don't have any accurate benchmarks? Really?


The only benchmarks done before adding it to the core were on maths-heavy code samples, something PHP is seldom used for.

You can read about it here: https://stitcher.io/blog/php-jit


I'm confused about this feature in general actually. Isn't the whole point of PHP's "simplicity" that each request creates a new interpreter process? So you're always in a "cold" state?


> Right now PHP 8 is in feature freeze, meaning no new features can be added anymore.

> Starting with new features, remember that PHP 8 is still in active development, so this list will grow over time.

Something doesn't seem right here :)


PHP 8 adds support for quantum superpositions. (Well, it does and it doesn't.)


Woops, forgot to remove that last line; thanks for pointing it out!


I've never quite understood the common reasons for bashing PHP. When I first got into web development, it was effectively the only real choice available. What it offered the beginner over the likes of Java and ASP (at that time) was ease of setup, a coherent model for simple data driven web page development (especially when compared to the likes of JSP), a great suite of built in functions, and comparatively excellent documentation. If I had to teach someone how to code now, I'd probably still consider PHP for the reasons above. Though Python has probably eclipsed PHP for many novice friendly reasons (docs and built ins).


I'm most excited about str_contains(), str_starts_with(), and str_ends_with(). Call me simple but I'm so glad I don't need to come up with weird work arounds for those functions.


For those who need them

EDIT: Actually, there are polyfills here: https://php.watch/versions/8.0/str_starts_with-str_ends_with


I'm eagerly looking forward for union-types since I heard first of them.

PHP APIs (both core and frameworks) suffer greatly from inconsistency. Union types in function/method signatures can greatly help static analysis. It is great that PHP gets this built in.


The thing I love most about PHP is that regardless of the new features they seldom break backward compatibility. I have a site created with PHP 5 that runs absolutely fine with PHP 7.0 and I don't remember we had to ever update anything in that huge codebase.

It's a pretty big achievement and avoids a lot of hassle for users as you don't have to maintain different versions of programming languages on a server.


I've had the exact opposite experience. It's unusual for an upgrade to not break something.

There are dozens of breaking changes in this release alone: https://github.com/php/php-src/blob/96c7d42a3ca9d822a08b3dd4...

Some of the changes are sadistic. "The precedence of the concatenation operator has changed relative to bitshifts and addition as well as subtraction." Have fun debugging code that worked perfectly well for years and now produces unpredictable results.


PHP7 will still be supported for a while. Debian will probably support it even further. You'll have a long ass time to fix these.

Even if you wanted to push the 8.0.0 to production as soon as it came out, you'd still have until November to run your tests on the RC branch and report any mishaps to the development team.

The backwards compatibility is mostly targeted to major platforms (Wordpress, Drupal, Magento, Symfony, etc).

> Have fun debugging code that worked perfectly well for years and now produces unpredictable results.

This describes my everyday experience with any language or codebase.

The cause for the unpredictable results are often human-related though, not version-related.

> Some of the changes are sadistic. "The precedence of the concatenation operator has changed relative to bitshifts and addition as well as subtraction."

I would gladly remove any code that does concatenation and math/bitwise on the same expression relying on the operator precedence. Sadistic is the person who writes these.

More than 2000 packages were analyzed and only 5 instances of that particular use were found[1], all bugs. This is a good change.

[1]: https://news-web.php.net/php.internals/105442


> > Have fun debugging code that worked perfectly well for years and now produces unpredictable results.

> This describes my everyday experience with any language or codebase.

That is horrifying. That should absolutely not be normal. I don't know what you work with normally, but it's clear that we are working in completely different worlds.


I don't know any programming context immune to human errors.

Stuff just breaks. Sometimes I get lucky and the guy before me wrote a cool test that prevents me from having to start a debugger, but the contrary is often the reality. OSS stuff is usually better, but not much better (OS upgrades always break, for example).


You're not likely to have something like the concatenation operator mixed with bitshifts. Most of the changes are more likely to be bugs in your code that remain undiscovered rather than things that worked perfectly fine before but are now broken.

These changes reflect how people use the language or what they already believe it to do.


You're talking about hypothetical code, but I am talking about actual code that worked fine but no longer works after an upgrade. Perhaps it was poorly written, but it was not buggy.

I can't think of a single time that I've seen a bug exposed by language changes. I have seen dozens of bugs created by language changes, however. (Mostly crashes).


If you're depending on very weird edge cases in PHP I'd consider that buggy even if it works.


This is a completely useless discussion if you're going to assume that code depends on "very weird edge cases" with no idea of what the code actually does.


You're welcome to post an example.


I love this too. Moving Pinboard from whatever flavor of PHP it was based on (in 2009) onto 7.3 only ran into two issues—something to do with the "explode" function, and requiring a certain kind of constructor in objects. All the rest of the migration pain involved libraries.

Granted, Pinboard is just a wrapper around some SQL queries, but that's what most PHP apps are. It was a big relief to find the migration so easy.


You should really like Common Lisp, then :) The language hasn't changed since mid 90s or so and many of the widely used libraries have gone for years without needing any changes.


You mean there is actually software out in the wild that is "done" i.e finished !


Likewise. I built a whole back-end in PHP 5 back in 2009 for a client. His front-end has changed a ton in that time, but the backend is still chugging a long in PHP 7 with no problems.


I with they don't do this. There are a lot of inconsistencies in PHP that should go away these days, but they still keep them because of backward compatibility.


But it does break a lot of times and still contains a lot of inconsistencies.


I would love to see PHP get some more/new love, it has a great community, fantastic tutorials and the package manager (composer) well just WOW!


PHP was just PHP for years.

Now I don’t even recognize what’s going on when reading code in a language I’ve used for my entire software development career.

It’s like a new language.

I want to be done with tech some days.

I just want to do my job, not relearn a language I’ve used for 20 years.


>I just want to do my job, not relearn a language I’ve used for 20 years.

Good thing is you usually don't have to, languages like php really try and makntain backwards compatability, so you _can_ keep doing what you're doing.

Even with some changes, companies rarely ride the wave and come onboard much later when major issues have been ironed out. Hell, there are PHP4 apps still out there


But that's a problem: it maintains backwards compatability with a LOT of well known problems/inconsistencies while introducing more features/inconsistencies for which you can just hope they don't mess up this time. It's a bit of good and a lot of bad from both worlds. I'm just so glad I don't have to use PHP anymore and no amount of a swine's make up will change this.


It seems every language has a group of people with an unrelenting urge to turn it into Java.


Really? What languages in particular? Even Java doesn't want to be Java anymore (see the "inspiration" it's taking from Kotlin and others in recent/next versions). PHP is the only language that seems to be chasing Java to me.


As long as weak typing is not abandoned, the Java-like language features are great.

I am really looking forward to generics in PHP.


Weak typing and generics, isn't that the worst of both worlds?


Keep writing php5, It’ll probably be the high paying FORTRAN gig of the 2040s


Why not just stick to the version you're accustomed to?


My prediction is that Annotations will be a game changer for PHP-based frameworks. Finally people will get something like in JAXR in Java, just being able to write @@Path("/users") over their listUsers function to have it be called when someone accesses the URL "/users" on the host.

Having to setup routing the cumbersome way has been the bane of being productive in Laravel.


Was it really cumbersome to declare a route in laravel? Isn't it just one line in a web.php file where you associate an endpoint to a Controller function?


The issue is that routes are declared in web.php.

In some cases, web.php routes aren't automatically updated if you use `artisan serve`, so you have to restart that sometimes.

And of course, it means there is a lot of distance between the file in which the controller and function are defined and the route definition. The route definition is in "routes/web.php" and the controller will likely sit in "app/Http/Controllers/Something.php", so if your Laravel project is moderately sized, you'll be scrolling a bit if you don't find the editor tab.


On the other hand, I don't think it's a good idea to mix the controllers with the route definitions. How I configure or set up the routes should not be in the controller classes, that should be a separate thing.

It's easier to see all the routes in that file instead of searching for them in the controller, especially as you said, in a moderately sized project, I can't be bothered to search or check the controllers. (You can counter argue that I can just Ctrl+F it). When you open up the routes file, you can see all your definitions in one place, which might ease the onboarding of new devs for example.


Well, I'd still argue it would be cleaner if they're defined at the controller (I would also say the controller does not define them, the controller has them defined as attributes to it's class). Java devs don't seem to have a problem handling the "look for what path this is" either, in reality it's a grep or global search from your IDE away to be found.

The routes file for any moderately sized project will likely be sufficiently complex that you cannot simply Ctrl-F it.


> Being able to write @@Path("/users") over their listUsers function to have it be called when someone accesses the URL "/users" on the host.

That is exactly how Flask works by using Python decorators, example:

    @app.route('/hello')
    def hello_world():
        return 'Hello, World!'
That would let you access /hello in a browser. There's also abstractions in place to prefix URL namespaces to a group of functions and add behaviors too (like requiring authentication).

It's nice, especially when the framework comes with an ability to get a dump of all of your routes / URL endpoints in a single command, along with what function it's associated to and the HTTP method. You end up not missing a single routes file that other frameworks have (Rails, Phoenix, etc.).


People already do that today with annotations in comments, at least with Symfony.


I much prefer the Laravel way, because it's much easier to get an overview of all the routes in an app. With your method you'd have to go through every single file! Most editors have "goto file" functionality, so you can type e.g. Cmd-P, "web", Enter, and be directly in the routes file.


Plenty of frameworks can spit out a list of all routes and some IDEs have tooling for that.


Wouldn’t using annotations for routing require the framework to pre-“require” every single controller though before matching? I haven’t worked with Laravel or Symfony but that seems super inefficient, particularly for sites with hundreds or thousands of controllers. Sure pre-warming exists that’s still a lot of memory.

The router we use, we setup in our bootstrap $router->set(“users”, users/listAll::class); and listAll is then only required when matched. Our controllers also receive a default route based on their namespacing so we only configure them if it varies.


For dev environments, the performance hit would be IMO acceptable, for prod you can generate routes already to not have to parse routes/web.php.

In theory if you have APCu or any other cache setup, you can use that to store routing information outside PHP, or just write it into a file. So only the first access is slow, then no longer and you can still manually scan if you can't find a function, controller or if you don't know the file involved.

It would atleast make code a lot cleaner.


I like the constructor property promotion, union types, improvements to exceptions and try/catch. Lots to like here.

Attributes worry me. Annotations are generally an eye sore to me, but in some places could be justified. For the most part, outside of Symfony, they were not used much. I'm worried that some developer will go bonkers with them, create a nightmare, and that will be the next legacy code base I inherit 5 years down the line.

Named arguments is okay I suppose, but IDEs solve knowing the order of arguments. I guess the IDEs will implement an auto complete for named arguments? I guess thats okay, but it will require more vertical code if you care about your lawn and keep your code in the PSR margins.

All in all I think this is a solid major, not the quantum leap we got from 5 to 7, but these are good additions. I'm sure we'll see plenty of decent additions in the minors.


> Named arguments is okay I suppose, but IDEs solve knowing the order of arguments.

Named arguments are incredibly helpful for functions with a bunch of optional parameters, like setcookie() -- instead of

    setcookie("cookiename", "value", 0, "", "", false, true);
to set httponly (the last argument), you can now skip over the unused parameters and write:

    setcookie("cookiename", "value", httponly: true);
Not only is this more concise, but it's also self-documenting!


I would have personally been happy with

    setcookie("cookiename", "value", , , , , true);
As I used in VB.Net 15 years ago, I have no idea if other languages (C#?) support that


Name parameters can benefit when you are reviewing code, beyond just when writing code; it makes clear what every parameter is for as you scan through code. This is most helpful with function calls with lots of optional parameters.

Another benefit is name parameters can replace the current pattern of passing a "parameter bag" array. Code checkers can catch mistakes here at time of compile, rather than runtime.

The negative of named parameters as implemented here is that the names are defined by the variable names in the function definition. So, renaming variables in the function definition will break code that calls the function using named parameters.


Named parameters along with property promotion allows for a pretty nice “Struct”-like pattern


for some reason (probably a bad one) i love switch statements and i look forward to the match expression


for whatever reason (also probably a bad one), i hate the syntax of switch statements, and for that reason i almost never use them. the match expression though, i'm actually very excited about. i quite like the mapped look; it seems more intuitive to read.


nothing wrong with switch statements.


Coerced-typed (weak) comparisons and easy accidental fallthrough are the problems commonly associated with switch statements.

The new match construct fixes both of these and is also an expression instead of a statement, allowing for more expressive code.


Hooray! Named arguments finally!


After years of being a laughing stock, it's nice to see PHP finally becoming a nicer language instead of basically being the "three languages in a trenchcoat" of programming.


I've used PHP for many years, but decided to stop in 2018 for my sanity. Surprised it has basic pattern matching now, it is good for people to stop using imperative and mutable code where it isn't needed. Anyway, since I started to play with FP languages such as Clojure, Elixir and Elm, I am not interested in most of OO/procedural languages anymore.


Any appetite to try Scala?


I dont see the big deal to be honest. If youre using == you're probably approaching the conditional too sloppily to begin with


When they add generics there will not be anything i really miss from other languages when writing php. Ok tuples or simple struct types (type enforced arrays?) would ne useful too, but phpstan/psalm can solve this problem too


What is the point of "Non-capturing catches"?

These kind of features would make debugging harder as people just ignore the actual error object and write weird common error message which could be useless.


> Note that void can never be part of a union type, since it indicates "no return value at all".

The empty set is the identity element for set union! It seems very weird to exclude it.


But "void" is not an empty set, it is no set at all...


if we want to squint and talk about sets and functions from sets to other sets...

  function voidy() : void {
    return;
  }
  
  echo json_encode(voidy()); // -> "null"
so i'd say that for most purposes

  void ≡ {null}
a singleton set, more or less[1], sometimes called a "unit type". that's because a void function does return something, it's just entirely uninteresting :) that's different from an "empty" type

  impossible ≡ {} // or ∅
with no values. there are no values of type `impossible`, so `foo() : impossible` can never return anything at all, like this:

  function foo() : impossible {
    while(1){}
  }
see mypy's `NoReturn`, Rust's `!`, Haskell's `Void`. it's used for giving a type to functions like `exit()`

[1] kind of, because it won't let you `return null` explicitly.


That's some huge release feature-wise.


Oh I read this as “What’s New in PDP-8?”

Was hoping for some awesome mods for a refrigerator-sized computer...


An ancient evil is awakening




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: