Property hooks mean that some language magic will turn a property access into a call to methods. It implies that `$this->x` has a different meaning if it's inside a hook or outside hooks. I've used this kind of feature (getters/setters) with JS code (and with Moose/Perl decades ago), and I wasn't convinced. Plain methods are more explicit, have less cognitive charge, and are easier to extend.
On the bright side, I'm glad that the language is still thriving. In 2021, I was worried when the foundation was created, especially as I read that Nikita Popov had left. He was the creator of PHP's JIT code, and at the time the only developer who could fully understand it. But it seems there was no need to worry. PHP is now longer "the elephant in the room" of web programming, but it's still a good language, with many active developers at its core.
It also gives static analysis tools semantic information about the structure of your classes. It can group pairs of methods that deal with the encapsulation of fields.
But as you said — it’s been there in C# for a while and imho it’s a good abstraction over getters and setters. Even 2005-era IDEs could manage it fine, making it easy to access the property’s get/set code, so that it wasn’t really magical.
Maybe it’s a culture thing — most C# devs use IDEs. Not sure what PHP devs use, but I suspect tools like PhpStorm will make this easy to work with somehow. Devs using no-LSP editors will likely have a different view.
Property hooks look awesome, they fix something that's my main pain point in PHP nowadays.
All these getters and setters manually coded make it feel like Java. Just completely boring and unusable without some fancy IDE that types all that boilerplate.
It is one great feature of C# that I'm glad PHP is adopting. This code is also easier to extend than the Java-like sea of getters and setters.
(I don't consider any mention of JS code as a valid comparison, if anything we are better ignoring JS existence unless forced to do some frontend)
"All these getters and setters manually coded make it feel like Java."
Project Lombok has solved that issue of manual boiler-plate getters and setters in Java. If you program regularly in Java it's worth having in your toolbox.__get / __set was doing that already and some frameworks very heavily rely on those.
> It implies that `$this->x` has a different meaning if it's inside a hook or outside hooks.
this is a valid critique but hopefully hooks will be super short and this won't be a major issue. Indeed, if your get is not an arrow function -- which only allows one statement -- then it needs a good thinking over whether this is indeed the best solution. Ie if your get is so complicated then perhaps a helper method is best and then you have get => $this->foo($this->thing) and that's the only place where $this->thing is special.
Even if a PHP project has a policy of short hooks, I think hooks impede clarity.
public string $countryCode
{
set (string $countryCode) {
$this->countryCode = strtoupper($countryCode);
$this->country = nameCountry($this->countryCode);
}
get => ...
In this short hook, the first line of the setter obviously uses the underlying property. But the second line of the setter...Does `$this->country =` use the setter even if it's in a hook (but not a `country` hook)?
Does reading `$this->countryCode` use the getter hook, even it's from a `countryCode` hook?
If not, is there a way to call the `countryCode` getter from this setter?
If quickly parsed the doc and the RFC, so I don't have answers (I suppose it's yes, no, no). But even if I knew how this code behaved, I would still think it's much more complex than plain methods.
$this->foo
would look for a getFoo() method, and execute if it existed, or not if not. Felt like that was easier to reason about, fwiw, but I couldn't get it off the ground. Even then, there were multiple C#-style get/set proposals floating around, so this style seems to be the one more people like. Not a fan of the style, personally, and probably won't use these much directly any time soon. If it helps people maintaining libraries that I use to deliver code that is cleaner and more productive to them... I'm OK with that.
This way, at least, it's much more explicit. And this should probably only be used inside frameworks anyway, and not in "user-land" code.
For a long time now, PHP has been on a trajectory of trying to be everything to everyone, constantly bolting on features from every language that happens to drift by.
My observation has been that the people who are deeply invested in PHP are tired of being hazed online for using a "toy" language, so they're trying to adopt all of the complexity and problems of other languages, rather than just keeping things simple, which is what used to be PHP's primary strength.
It's not for people that compulsively talk about category theory and lenses five minutes into every programming conversation.
PHP to me, professionally, is nothing without Laravel. So as long as Laravel doesn't become more obtuse than it already is, it's all good.
I really dislike getters and setters, particularly when they allow async code. Now all the sudden you have a massive performance risk, it's all too typical to see junior devs doing expensive stuff in getters and now the whole application, exponentially, becomes slower.
Anything that _may_ involves magic is dangerous in large code bases.
Worse than that, it is possible to read it wrongly which is going to cause many nasty headaches for amateur developers of the future trying to debug PHP code.
I'm not bringing this up as a particular criticism of the language, I think it's fine. It is also an experience I have with lisp, where it is fun and easy to write but hard to read when coming back to it after a while away. I just don't think php is a simple language, on several levels. The semantics that I mentioned, combined with the mixing of paradigms, and the large and inconsistent standard library. You can write simple php but it takes a lot of discipline.
PHP:
- Easy to deploy: Upload files, done.
- Easy to develop: Reload page, see changes.
- Lots of HTTP tooling built in.
- Fast.
Python: - Great language.
- Great code reuse system: Modules.
- Nice framework: Django.
- Less breaking changes in recent years.Slim is a pretty nice framework: https://www.slimframework.com/
The thing (most) other languages have is unicode support and concurrency. In PHP there is basically none of these.
Fast? You mean fast as in CPU bound tasks? 99.99% of PHP code is slow because of IO, and without any concurrency all the other languages beat PHP easily. If you need CPU bound work, you would not pick PHP (or any other scripting language) anyway.
In most benchmarks PHP (with Laravel/Symfony) is barely doing 500req/sec. Compare this to languages in the same space (like nodejs/python) and they run the same program and can serve 10K-30K req/sec.
Having said that python (a slow langauge) is still capable of doing heavy CPU bound tasks with libraries like numpy. Im not aware if PHP can install C dependencies with composer, like you can with pip.
- https://www.php.net/manual/en/book.ffi.php
While I'm at it:
This should work in Python, too. With Django, I think you need to use https://pypi.org/project/django-browser-reload/, and rith most other frameworks / WSGI servers just try adding --reload flag.
Edit: Django should wor out of rhe box actually – that package is for refreshing the page in browser.
> Easy to deploy. Upload files, done.
I can see the appeal, but generally you’d want to avoid that (for anything other than quick prototypes, maybe). Set up a CI, push to deploy. This goes for modern PHP as well.
If you want something simple to deploy webapps and know a little Docker, I’ve built a deployment tool you can run on your own VPS: https://lunni.dev/. (Feel free to reach out if you need any help!)
But in PHP you have it out of the box. Faster, with less complexity and less resource consumption. And you can use the same setup in development as you can use in production.
I found myself getting sucked in into a complex project structure and dealing with all kinds of strangeness like "artisan commands", "the autoload cache" etc.
With Django, I can build a web application in a single file that has "import django" on top and take it from there:
I know people love to say this, but does anyone realistically make websites or web apps that way? No, not really. Even with PHP there are frameworks, there is a package manager, there is version control, and there are deployment systems.
Pretending that PHP developers are uploading a .php file to a shared hosting server (like in 2002) to suit the narrative feels disingenuous to me as it doesn’t align with what I see PHP developers doing at all.
In PHP, I do. In other platforms, no. My personal PHP site is published by a git push to the server.
You are correct in that a lot of PHP use now is larger frameworks with asset compilation and cache clearing etc, but even when developing on large systems like that it is nice to sometimes be able to just manually tweak a file and refresh.
For R&D and quick tests, just uploading a quick & dirty php file to the server is a very useful language feature to have IMO.
I actually like PHP a lot, and it's amazing how far it has come in the past 10 or so years, I just think way too many people assume you get the 2004-era PHP simplicity with all of the 2024-era PHP refinements, and you really don't. There's tradeoffs.
How’s php’s?
It is? I never had problems with poetry. Though I agree that there are mroe options than necessary.
Sure, it works for simple/less important cases. But it also means that your application code is inconsistent while the files are uploading.
Stop your service, upload the files, start the service: safer.
For a Django app you would upload files and ask Gunicorn to graceful reload... similar, just cleaner.
In practice, any serious project is likely to be version-controlled. Git pull is generally fast enough that it behaves like an atomic change. (By default, opcache will not reload a file that's less than 2 seconds old.)
But who cares, we are literally talking millisecond differences between them all. Throw a reverse proxy, DB into the mix and a few packages and they are all slow.
I wait 1-3 months, but then update. It used to take way longer, because Amazon's Elastic Beanstalk platform would take longer to update, but I've now changed to Platform.sh and the transition should be easier.
It has been very backward-compatible (i.e. stuff that works in 8.n also works in 8.n+1; and unless you use exotic functions or are relying on special functionality, it should work for you, too).
Once I'm at 8.4, I would slowly update the code / syntax with rector and the assistance of phpstan.
For framework updates I wait 1-2 patch versions before updating, because of composer dependency problems and sometimes bugs do still find themselves into new releases (e.g. I would wait at least until Symfony 7.2.1 before upgrading from Symfony 7.1.x).
It also often fit with the current Laravel version (11).
I enjoy the PHP 8 new features such as named arguments, constructor arguments promotion and nullsafe operators. Made my new code a lot more readable.
I am not that sure about 8.4 yet, though the new array_ functions and new DOM look interesting.
We upgrade the development environment around the time when our tooling (phpstan, cs-fixer) runs on the next version, but doesn't necessarily support new language features.
We upgrade the production environment when our tooling supports most of the new language features and at least all of the ones we want to make use of.
This usually happens within 3-6 months of the release. By that time the version has stabilized enough to be safe for production use.
I still have a PHP5 project that somehow still runs.
As long as you do not use the new functionality, I'd claim that a new PHP version is no less stable than an older one. And on a contrary you would be missing out on some bugfixes that were deemed too risky to apply to an existing version.
Disclosure: I've got a commit-bit for PHP, so we had in-house expertise to diagnose issues ourselves.
I guess depending on the app that might not really matter, but that seems like it could be an issue at some point.
Also external tooling, like for example NewRelic extension, takes some time to release a version that supports the new release.
When a hook is called, inside that hook $this->[propertyName] will refer to the “unfiltered” value of the property, called the “backing value.” When accessed from anywhere else, $this->[propertyName] calls will go through the relevant hook. This is true for all hooks on the same property. This includes, for example, writing to a property from the get hook; that will write to the backing value, bypassing the set hook.
A normal property has a stored “backing value” that is part of the object, and part of the memory layout of the class. However, if a property has at least one hook, and none of them make use of $this->[propertyName], then no backing value will be created and there will be no data stored in the object automatically (just as if there were no property, just methods). Such properties are known as “virtual properties,” as they have no materialized stored value.
Be aware, the detection logic works on $this->[propertyName] directly at compile time, not on dynamic forms of it like $prop = 'beep'; $this->$prop. That will not trigger a backing value.
Feels like too much magic to me that a property access can mean different things depending on context, but I'm not a PHP user, so I don't get a vote.The backing value is effectively private to everything but its own get/set methods, that seems fairly straightforward to me.
In fact, you can imagine what their argument WOULD have been if setting `$this->countryCode` inside the setter for `countryCode` DID result in infinite recursion.
When it comes to PHP, whatever it does, on HackerNews and in the rest of the industry, it just results in a bunch of people complaining about it. Disappointing, and unprofessional.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-...
Conversely php already has other places where context affects property accesses, and IME it's not the problem you make it out to be.
I've never been a fan of this kind of magic, and I wonder how other languages deal with this case.
self.__dict__['property_name']
And if those PHP rules were in python you could just write: @property
def property_name(self):
return self.property_name
In actual python though, that would infinitely recurse.In my projects I sometimes emulate getters and setters using `__get()` and `__set()` but that's heavy-handed and requires lots of PHPDoc annotation for type checking. Property hooks look awesome!
I know the textbook answer is so that every single possible property can become some mutable chain of events so you can swap names or side-effects without the caller knowing, but I've yet to find a use for that in real life.
It just leads to builder patterns and other oddities like forced decorators like Java has everywhere. I felt like beans were the realization that perhaps we shouldn't be doing this.
It makes for a cleaner OOP-y interface in which the caller only cares about actually exposed properties and not methods to get and manipulate hidden properties.
IMHO using properties directly is a much more natural way to talk about objects, than having a bunch of methods to get properties. Getters and setters also help ensure that methods are only for changing an object's state, not getting an object's state. For example:
class User{
public ForumsPost $LastForumsPost{
get{
if(!isset($this->LastForumsPost)){
$this->LastForumsPost = <get from database...>;
}
// Return the cached property so we don't keep hitting the database.
return $this->LastForumsPost;
}
}
}
print($user->LastForumsPost->Title);
print($user->LastForumsPost->PostId);
// instead of...
print(($user->GetLastForumsPost())->Title);
print(($user->GetLastForumsPost())->PostId);I wrote about it here https://technex.us/2023/07/php-attributes-are-so-awesome-i-j...
It sounds like you got the gist but somehow you are in an area of programming where getter/setters aren't useful.
That's fine and okay. Part of growing up as a programmer is realizing your niche.
Most of the advice out there is deep, not broad. It's deeply connected with our niche and not necessarily broadly applicable.
seemed like a way to backport poor librar/framework choices to have IDE support but not for new code
Another pet peeve of me is that the global namespace is littered with these utility functions that should be easily composable or maybe be methods on the objects themselves - and looks like PHP 8.4 adds four more `array_*` functions. For comparison, Python's builtin namespace has a total of 71 functions and a couple of exception classes. PHP's builtin namespace has more functions for dealing with arrays and now 58 of those are prefixed with `array_`.
It’s hard to build on a language used by so many, when you can’t modify the base. Python decided to do 2.7 vs 3 and fragmented the eco system terribly.
Adding any globals should be a carefully-considered change. User-defined functions are global by default, and although there are (now) much better ways to write PHP libraries, I can absolutely see some old library defining array_find (one of the new global functions in 8.4) in an incompatible way and breaking new code that attempts to use the built-in function.
Sure, you can’t touch the existing pile of globals, but at least stop pouring fuel on that particular fire…
The design philosophy of PHP is to include whatever common methods would otherwise be in a popular library. (PHP actually began more as a library than as a language.) This differs from, eg, Python, but doesn't hurt.
The decision not not to make methods on the objects, but to include everything in the main namespace (so array_walk instead of Array.walk or Array()->walk etc) is another function of the same philosophy. It may not fit your idea of cosmetics, but there is nothing wrong with it.
On the other hand, I would love if PhP gained chainability ([].array_map.array_find()) and then the names would be a pain. If that ever happens there are solutions.
Someone else creates a function named array_something in the namespace. Maybe it already exists in earlier versions, maybe it happens to collide with one of the four introduced in 8.4. This function is accessible to you in the current scope. Now, you try to call the function like the way it is defined in the standard library. You get a very confusing error and spend 10 minutes trying to figure if it is you or PHP that is hallucinating. Turns out you have been inadvertently calling that other user defined function. The other user may be completely unaware of the fact that they created a function with naming collision.
To combat this, you need strong IDE help including static type checking, which is not always there for everybody. And it still doesn't help with cases where the user defined function collides with a new standard function.
Most "modern" languages have very few built-in functions in the global namespace. Another example is Go. Correct me if I am wrong, but I believe there is 0 function in global namespace in Rust. println! exists but that's a macro. In other words, the example I mentioned just never happens with these languages.
Not to mention the long list of junk you see in IDE when you type "array_".
I guess you haven't written much MATLAB.
With predictable results.
The difference between languages like PHP and more modern languages, is that the more modern languages have more airbags, for the bad code. It's still bad code, but it won't do as much damage.
PHP is likely to be around for a long time: https://w3techs.com/technologies/history_overview/programmin...
So it developed features and functionalities as needed with a very pragmatic focus [0][1]
[0] the most clear example to me is that since functions are not values and cannot be assigned to variables the way to store a function in a variable is to simply assign its name as a string so $callable = "array_map" works. Or that the way to create a pointer to a method is to create a 2 element array of the object and the method name. I like this example because the way method pointers work in JavaScript is objectively worse as the "this" is easily lost. Some languages are built on CS principles and PL theory, others like Bash or PHP are just built to get shit done. I am glad that recent versions are fixing some of the oversight of this approach while keeping the pragmatic culture
[1] I am not sure of how true it is, but some claim that some of the standard functions have irregular names because the interpreter used the name length as hash key
Great metaphor. I might steal it for some model contract terms I'm doing (for an expanded version of my contract-drafting course materials). I'd been thinking of "guardrails," but "airbags" is far better.
People building and creating awesome new things? Increase in happiness and empowerment? More efficient processes and increase in productivity? New businesses being born? Wealth and value being added to society?
PHP lovers generally don't like acknowledge that, but the PHP we've learned back-end development two decades ago is no more and that it's now as beginner unfriendly as Java was when we picked it.
It's a pity because there's nothing as beginner-friendly anymore. I think the blame is on people calling themselves “PHP developers” who never bothered learning more advanced languages after PHP and instead pushed PHP to reach parity with those, at the expanse of losing its soul.
I've done so periodically, and every time I go "this sucks, gimme the tooling".
What's sad is that it's not how people use and teach PHP today.
PHP's magic really is that you can write small scripts super easily to do small tasks, but somehow most PHP developers insist that “no PHP isn't for building small scripts” but “a real, professional back end language ready for mission critical enterprise requirements blah blah blah”, because surely that make them sound more serious as programmers, missing the point entirely…
(And sorry to all insecure PHP programmers out there, but for serious stuff using PHP is still equivalent to coding with handcuffs and you should really learn a second programming language at last because being a one trick poney really isn't as cool as you think it is).
I also use it to write CLI scripts to exchange data between programs. The wealth of extensions and good UTF-8 support are a plus.
The difference between it and Java is you’re not forced into the ClassObjectGetterSetterPropertyHookFactoryBean paradigm with PHP. You can continue to write concise, simple, elegant scripts that read from top to bottom and serve one page and serve it well. You don’t have to use any of these crazy newfangled features - I, for one, will be using none of them, and will be sticking to my if-else blocks and nested for loops that will be easy to read and grok when I (or someone else!) come back to the code two months down the line.
While PHP can still be uses like that today (and is still unmatched in terms of ease of use for simple stuff when used like that) it's been a long time since the PHP project and developer community stopped caring about this use-case.
If you write JSP, you don't even need that.
Not only is it yet another global function in a namespace already chock full of random array helpers, it is extremely similar in both name and usage to array_search - a global function since PHP 4. Except, of course, that in typical PHP fashion, array_find’s argument order is ($array, $filter_callback) while the older array_search is ($search_value, $array).
There are literally hundreds of hits for existing, global, functions named array_find. If these are loaded from a library, they will break uses of the new built-in function in exciting ways. Yet, even with this mentioned in the RFC (https://wiki.php.net/rfc/array_find) it seems to have been no obstacle whatsoever to its inclusion - despite the fact that the implementation is literally three lines of code.
I have to question if the benefits of this global function really outweigh the benefits. PHP devs claim that other languages have these functions so PHP should too - but neglect to note that most languages don’t make them global functions (rather, they’re usually array methods or in some utility module).
The backward compatibility section found only 200-ish projects where array_find() was defined in global name space. For me that's a small price to pay for introducing the new function, and refactoring should BE easy when upgrading a project to PHP 8.4.
Adding array_find() to a namespace would be inconsistent. All other array_*() functions are global.
But I agree, there is already some inconsistency, and when adding a new function you have to choose which function to make it consistent and which one to make it inconsistent with.
Also people should be coding defensively with things like “if not defined” when implementing their own global helper functions (or avoid doing that at all)
webRTC is a beast with the STUN server needs better handled elsewhere.
Security: 31 Dec 2028
Bug Fixes: 31 Dec 2026
Readonly has been discussed but it wasn't part of the property hooks RFC and is a separate issue/feature. This is just a natural consequence of having private setters.
> but you’ll never have to use them
But i do. I now cant tell if im accessing a property or a getter. With custom functions (like getFoo()) it was annoying, but still obvious, now its just magic and library authors will 100% start to abuse this feature allover.
get => \sprintf("%s_%s", $this->languageCode, $this->countryCode);
in the first code example? Is it a lambda?
https://wiki.php.net/rfc/property-hooks
It follows the syntax of arrow functions
No it’s not: it’s a MINOR update.
I didn’t know what they were, so I clicked. I was bewildered that I had never run into them before, used them in my own code, or seen them used by others. Come to find out they’ve only been around for about a day!
Reminds me of some of the lovely expressibility and syntactic sugar that’s pulled me to other languages lately. Glad to see it make its way into PHP.
$foo[1:-3:2]
Instead of the usual array functions, which could stick around for BC. That would be amazingMy personal motivation was always to finally put an end to the getters/setters boilerplate.
In case people aren’t aware, DOMDocument is dangerous. You can’t parse HTML with an XML parser; so everyone currently using DOMDocument for HTML would benefit by replacing that with DOM\HTMLDocument immediately, eliminating both security and corruption issues.
Have you tried using an HTML parser?
variable-length lookbehind assertions are now supported.
yay! I needed that so many times.
But I agree, a great feature!
https://github.com/rectorphp/rector/issues/8701
https://github.com/nikic/PHP-Parser/commit/7b0384cdbe03431c4...
Really good thing when doing some operations on monetary values. No need to use bc_* functions anymore it seems.