I'm using Laravel/PHP for a new project and it's been a joy. A true joy. After spending the last 6+ years writing backend services in Node, PHP feels like a breath of fresh air. No restarting the server, no compiling errors from babel/typescript wackiness, no blocking threads, server-side templates out-of-the-box, and so much more.
PHP has come a really long way, I really hope to see it's resurgence some day after everyone has been burned enough from running JavaScript as their server.
It's so nice to see a comment giving PHP the praise it deserves. Honestly, PHP is a good, if not great, language to use for building solid web apps fast.
People seem to love to hate it because it's the "cool" thing to do. Yet PHP developers continue to ship things faster, while JS devs are probably still fiddling with their Node environment setup...
> People seem to love to hate it because it's the "cool" thing to do.
While I agree with this, I think the tone is slightly dismissive. From what I have seen, older people in our trade seem to recommend against PHP due to it having a terrible relationship with consistency, functionality, performance, etc. in its history. Though I have (thankfully) seen that the language and its standard library has undergone several large improvements, which is great to hear.
> Yet PHP developers continue to ship things faster, while JS devs are probably still fiddling with their Node environment setup...
On your point of JavaScript, the build environment nonsense can definitely get hairy. It's why we get things like Deno, which attempt to throw all this cruft away and start again. And sometimes that's a good idea. If you're dedicated to Node, replacing Webpack with Rollup seems to be what is generally recommended. The only obvious disadvantage there is compatibility with Webpack plugins.
It would be nice to have a type-checked JavaScript variant with a practically non-existent build environment (no Webpack, Rollup, etc.) As much as I adore TypeScript, the compiler itself is massive and takes quite a long time to even start.
> From what I have seen, older people in our trade seem to recommend against PHP due to it having a terrible relationship with consistency, functionality, performance,
As an older person in the trade, I don't agree with the other older persons. Only consistency is a problem with PHP code, and that is largely NOT caused by PHP. Inconsistency is the product of developers coding without any real thought about how to abstract things (ok, well, maybe not in the case of magic strings). You can do this with every language. Some languages do everything possible to force consistency, and developer still find a way to be delightfully inconsistent even with the syntactic equivilent of bowling gutter bumpers (see Cobol, Go, Java). Consistency is a developer problem. You can write great code in languages that are terrible.
PHP has never been slow (compared to other dynamic languages), or lacked functionality. If there is a rub on PHP it comes from no separation of code and presentation, which flew in the face of the MVC pattern which was THE WAY for a very long time. Now... well, JSX much? Anyhow, my team works with Go, JS, PHP and Python, and the code that takes the least effort to both extend and maintain is... the PHP.
I am honestly and truly trying my absolute best, but no matter how hard I try, I again and again completely fail to sufficiently and comprehensively put into meaningful words how the inconsistency of the PHP language doesn’t play a role AT ALL when building actual web applications for actual users.
It just. Doesn’t. Matter. Choose Symfony or Laravel, and you are in for a wonderful development experience, from setup to dependency management to architecture to implementation to testing to deployment – for certain kinds of projects it’s just perfect.
I agree with you, and it's super hard to explain. But if you have the right type of project requirements, Laravel is unbelievably great to work with. I love other languages more than PHP, but for a real world, client facing project that I want to be mostly hands off, Laravel would get my vote 9/10 times.
I think you've sufficiently and comprehensively put it into meaningful words above!
The truth is, those who care to use the language properly know this already. Those who wish to dismiss it always will, and this happens to be an easy angle of attack.
They are different, currently no Deno registries have dynamic version resolution (no greater than operator). Once you have locked in on a version you are in it for good unless you change it manually
However if the argument is: updating libraries break stuff, that is gonna happen every time in every language. There is no guarantee the next version will just work as the last one did
Not only shipping things faster but testing faster, scaffolding faster, debugging faster ... the tooling for PHP is much more mature than it was 6-years ago and there are so many GOOD packages out there that haven't been forked and copied 20x over.
Really happy to be working with it again, even if on the side for now.
I can hire a top-notch PHP engineer for half of what a mid-level JS engineer would be asking.
It's not that PHP engineers are less qualified than JS. I think bootcamps shifted the market for JS developers and now really good engineers cost an arm and a leg while good junior engineers start around the $100k mark. The whole JS salary market is insane and as a startup, I can't afford it right now.
I think it’s interesting to me, as I see these comments a lot with PHP specifically and there is at any honest pushback on this, so here’s my attempt:
Just pay what good engineers should be paid. If there are PHP developers out there not getting the same salary as a their peers like this post mentions, you should leave that job for a better one. Please demand better, PHP developers, for all of our sakes. Business always wants to put downward pressure on salary and we need to be united against this regardless of preferred tech stacks
I agree but I'll counterpoint for just a moment. A lot of mature PHP engineers seem to be from Europe, or rather non-American. I'm often finding it's American salaries that are crazyyyy high, but factor in that health insurance isn't spectacular here it might all balance out.
I've run no numbers, I have nothing but infrences to base this on, but hiring a mature PHP engineer in Europe would 100% be cheaper in the long run than hiring a junior/mid-level JS engineer anywhere else.
There's an interesting comment/quote on an Hacker News post about Perl's "Laziness Impatience Hubris" mantra that I think of when people talk about developer speed.
This might be true for the web but for CLI apps etc I don't think this holds the case.
It’s exactly 180 degrees for me. Node js just seems to be super fast. And with typescript its heavenly.
I don't make a website and working on node js is fun. In PHP it is like doing something esoteric. Just a simple argument parsing is so hard in php compared to node js. In nodejs I use meow and even without docs, I can parse cli easily. In fact, I think Rust can be more easier than PHP in many cases. I usually rewrite in rust for long term daemons. Also in php I need to install php I don't know why I should install php-pdo etc. I mean why not just allow composer etc to handle like just like node do? I am frustrated with php stdlib which seems to be fossil at the moment.
The thing I like about PHP is laravel framework where I can set up websites instantly. Node js is fragmented with adonis and many other micro-framework.
Anecdotal - my experience is the opposite. I have two large PHP side projects currently (vanilla and Drupal) and I find working with PHP and Composer to be a much slower experience overall than my day job developing with TypeScript/Node and JavaScript/React.
I would guess that a lot of the slowness is not from PHP itself, but the way your specific projects are using it. With the vanilla PHP project, the slow down may be caused by poor design decisions from other developers.
With Drupal, the code quality of the core is generally okay, however the added inertia may come from a "square peg, round hole" situation, where the CMS is being used for an obscure purpose for which it wasn't really designed. This is quite common in the wild, probably due to the low barrier to entry and the fact that people will use what they are comfortable with to solve every problem under the sun (not dissimilar to the prevalence of Excel throughout the world of finance for a variety of completely inappropriate use cases).
Much more than most other languages, PHP is purpose-built for serving web requests.
For example, PHP could get along without async/await and promises in a lot of situations, because threading was effectively subcontracted to the underlying web-server. You could just treat, say, a curl call as blocking-- resulting in a simpler code flow-- knowing that wouldn't lock your entire web server.
I'm writing PHP8 with the Symfony 5.3 framework at present too, and I'm also liking it. Provides what I need to build with and otherwise stays out the way.
The improvements over the lifespan of PHP7, and the new things in PHP8 make PHP such a nicer language to work with.
Makes it sound like the underscore replaces the decimal, which it doesn't. The underscores are simply ignored by the PHP parser, so that 10_0.1 === 1_00.1.
You could afterwards use PHP to replace the `_` with a comma for display purposes, and I assume that is what they are trying to say.
Yeah, that's a terrible example since some places do use comma as a dollars/cents separator, and others don't. And some people use floats for currency (with the obvious caveats), and might read this as "_ is the same as a decimal point".
They really should just use a simpler example, like 10_000_000 being easier to read as "10 million" than 10000000.
> They really should just use a simpler example, like 10_000_000 being easier to read as "10 million" than 10000000.
Declarations such as `$million = 1000 * 1000;` or `$seconds_in_day = 24 * 3600;` are very common, and in my opinion more readable than the ignored-underscore syntax.
Yea, Credo[1], one of the static analysis tools for Elixir specifies it as:
Numbers can contain underscores for readability purposes.
These do not affect the value of the number, but can help read large numbers
more easily.
141592654 # how large is this number?
141_592_654 # ah, it's in the hundreds of millions!
Like all `Readability` issues, this one is not a technical concern.
But you can improve the odds of others reading and liking your code by making
it easier to follow.
Should make it more obvious that it is purely a readability thing, and that is obviously subjective anyway
My absolute favorite thing about PHP is the arrays and the ease of working with them. Whenever I find myself working in another language dealing with loads of data I'm immediately thinking of how easy it would be to accomplish it in PHP.
And I've been loving all the new additions to PHP over the last few years as well. Version 5 was rather limited but since 7 it has grown into an actual programming language for which I feel I don't have to apologize for.
Is it really useful to have ordered map as the "only" collection type?
I guess it might be Stockholm syndrome - but I'm quite comfortable with a "list/array" type (numeric keys, ordered) and a "map/hash_map" type (objects as keys).
That's indeed a case where it fails, but in all my years I have maybe ran into that problem once. But it's trivial to implement a more strict form of array if you wish. And if I remember correctly there are some standard extensions that have classes to do just that.
And for the record, it's not Stockholm syndrome, I use plenty of other languages and I know the benefits and drawbacks of each of those.
I've never understood why some programmers like to use ligatures, especially on a cheat sheet like this, which will be used primarily by people who aren't familiar with the syntax.
It's not 'a' ⇒ 1, it's 'a' => 1, just write it out the correct way. Why are you trying to be fancy?
I remember inheriting a RoR v2 based project. Ended up virtualizing the entire server to migrate the damn thing as it was a big pile of dependency mess to port to a newer server stack. On a similar situation with a PHP 4 based codebase, adapting it to work on PHP 5.6 was a few hours work. Done. No other language can beat that. And thanks to a newer (and more open minded) generation of developers, PHP has a long way to go. The launch of the PHP Foundation by Jetbrains, Automattic and others - https://blog.jetbrains.com/phpstorm/2021/11/the-php-foundati... - is also a step towards a better future for PHP.
I really want to use PHP for one-off CGI scripts, (rsync files and done, deployed), but I really wish it had methods on primitive types. It hinders discoverability. It's annoying having to look up which function I need to use, and to find that there are many alternatives, most of which are deprecated.
I agree, it'd be nice if the built in was more standardized and had more features.
However you do have options to choose from with php these days. Really well maintained libraries exist for basically everything you could want, often they are fast, well tested and modular. And it's nice because you can even choose the style you prefer with this.
However I don't think it is something that will ever be done, designing a good standard library is quite difficult, especially by email and rfc.
I think it is better if the community designs one that gets a lot of traction to become de facto standard. All the large frameworks already has their own standard library.
With the performance improvements to PHP over the years it is no longer a detriment to performance to write a standard library in PHP.
And if we can get the operator overloads rfc passed we can have userland scalar objects
The evolution of PHP has shown the difference that having engaged stewards of the language can make. Saw a list of quotes[1] from Rasmus Ledorf which I think explains it's stagnation. As someone who used to sneer at the language, modern PHP doesn't look out of place among Ruby, Python, etc.
I don't know how this really played out internally, but from the outside it feels like Hack/HHVM kicked the PHP core team in the gut and inspired them to improve things.
The guys behind it work at Spatie[1] which you have probably heard of some of their packages, and Freek has a blog[2] that has a lot of PHP stuff on - lots Laravel, and lots just general new language stuff (covering PHP8 features etc)
PHP should have chosen to undergo a rebranding a few years ago, if you ask me. The stigma it has to deal with is probably unsurmountable and will be forever. If you think PHP, you think WordPress and Joomla, and that means "hacks and vulnerabilities"...
It's a good language nowadays, with quirks like any other language, but I still have one big problem with it: There are too many "PHP developers" out there, and most of them are very bad, and many of the good ones are from poor regions in the world and you can find them on Fiverr doing kick-ass work for a grand total of $50.
Having been out of PHP for several years now, I assume that needs a === instead of ==? It's unfortunate that we have the need for a ===, but it's no different that JS in that regard.
The above comment says: "many of the good ones are from poor regions in the world and you can find them on Fiverr doing kick-ass work for a grand total of $50. "
PHP's main problem is its very shallow learning curve.
The 5840 built-in functions provide easy ways to get many useful things done with minimal dabbling.
In other words, one can be a "scripter" instead of a "programmer", and for many projects that's 100% OK.
Other languages automatically filter out "scripters" from their field by demanding a certain level of mental abstraction to produce anything moderately useful.
While there is absolutely no difference between a good programmer using PHP, or a good programmer using any other language/environment, but there is a big difference between the median levels and below.
This in turn lowers the reputation of the field, and it becomes uncool to put PHP on one's resume, therefore the more capable programmers propagate out to other languages, which further lowers the median, etc.
The reason I never use Heredoc is because you need to abandon your indentation, otherwise your tabs/spaces get included in the string. Is there a way around that?
I've gotten into the habit of generally using single quoted strings (with 'around them') which alleviates most problems with escaping double quotes. And for the odd string that needs to have a single quote inside I switch back to double quoting.
This approach also has the added bonus of stopping PHP from accidentally evaluating something inside the strings.
Genuine question from a php hobbyist : what is the equivalent of Typescript’s ability to declare an object’s structure?
It’s really weird to me, I mean don’t we do this all the time? Work with eg. an $options array/obj passedto a constructor, or say, a message decoded from JSON…
I could write $name = $message[‘username’] … and there is no checks in ide or runtime, while the phpdoc will just document $message to be an object or array… what am I missing?
It looks like php devs create full blown classes to represent just about every data strcuture, but what if it’s just data and you don’t need any attached logic’ Isn’t there a concise way to declare a complex type?
Can you directly cast an object / assoc array to an instance of such a class?
If I have a function that receives eg a Message, it means an instance of the class right? So somehow my assoc.array/object still needs to be instanced, and if I do just $message = new Message($theData) … it doesn’t auto assign properties right? That would be handy though still very much boilerplate.
I guessthe language is just designed for how it’s been used so far, may e it will change if JIT makes php more open ended in its uses.
I never had to do this and I don't believe you can do this directly via a language construct but you can do it within a class via a method or trait or static function. This trait can then be applied to any class. Probably be better though to just have a create function that takes an input of type and coverts to class.
Anyway I was curious so I wanted to try this out with the trait method here is working code that illustrates this.
<?php
/* trait to cast from any iterable to class */
/* reusable - close to what I think you are asking for */
trait castFrom
{
static function castFrom($data)
{
if (!is_iterable($data) and !is_array($data) and !is_object($data)) return null;
$class = new self();
foreach((array)$data as $key => $value)
{
if (!property_exists($class, $key)) continue;
$class->$key = $value;
}
return $class;
}
}
class Foo
{
use castFrom; // use the castFrom trait
public string $str = 'blah';
public int $num = 5;
public function hello() { echo "{$this->str} : {$this->num}\n"; }
}
class Bar
{
use castFrom; // we can use the castFrom trait again and again
public int $x = 0;
public int $y = 0;
public function hello() { echo ($this->x * $this->y) . "\n"; }
}
$data = ['str' => 'foo', 'num' => 7, 'x' => 3, 'y' => 7];
$foo = Foo::castFrom($data);
$foo->hello();
print_r($foo);
$obj = (object)$data;
$bar = Bar::castFrom($obj);
$bar->hello();
print_r($bar);
/* you could just use create functions form the class */
class Creator
{
static public function createFromArray($data) {} // create from array
static public function createFromObject($data) {} // create from object
static public function createFromSerial($data) {} // etc..
static public function createFromJson($data) {}
}
EDIT: Added ugly check to make sure the type can be iterated over.
is that creating a JS class under the hood or is just a hint for the compiler?
What I do , but I don't work with recent PHP versions is to create this as a class, then to make this easy to construct objects from JSON i add a static function fromObject or fromJson that does it for me. Using real classes could prevent bugs when working with shit APIs like Microsoft TTS , where they have 2 endponts and one returns objects like voice: {name:"Bob"} and the other voice: {Name:"Bob"} so my code will wrap both type of responses into a well defined class.
I don't think there is a PHPDoc annotation just to hint what that object looks like but I will be happey to be shown a way.
Simple object type in TypeScript, the "type checking" abstraction layer on top of JS, which actually doesn't even need to be compiled (eg. esbuild strips all typing from the code before compiling).
Your approach is sensible. I remember using json_encode() indeed so I could declare some data in a php file with <<< HEREDOC in the Javascript short syntax (though short array syntax in php nowadays makes it less painful, JSON syntax still a bit less verbose).
I checked that example in TS playground and it does nothing when transpiling, so is only a compile type check. From my experience when I have an option object with many properties I would create a class both in PHP and JavaScript, usually functions that need an options object are very complex and many times you need to add even more options and having a class make it simple to do the changes and refactor.
You can get some basic checking, but not type in arrays [1]. Maybe using attributes you could check if it is?
class TFooOptions
{
public function __construct(
public bool $enableFlag,
public array $userIds = [],
) {
}
}
$options = new TFooOptions(
enableflags: true,
userIds: [1,2,3]
);
new Foo('Bob', $options);
Or if just for IDE checking, you could use the @property docblock value on the class.
You can force a type check that it's a specific type of object or interface rather than an array. But, no, you can't do what you're asking for directly.
The language type system doesn't quite support that yet in all scenarios. As of php 7/8 it's getting there but for what you are describing you'd need to use a static analysis tool still unfortunately.
Here's two of the most common ones. These are very mature and are very broadly used. Most editors also come with some support for these annotations so you often get help in the editor when something is wrong.
I feel like TypeScript and Flow went down the structural typing path (rather than relying on nominal types) because they were following what was popular in JavaScript at the time, not because it is an unequivocally better solution. The last time I programmed PHP, I didn't feel having to define lightweight classes was a big deal.
The examples you mentioned are interesting because I consider `options` arguments to be a code smell that tends to happen because TypeScript is missing named parameters, which PHP has. And typing JSON messages is far from a solved problem in TypeScript, because there is no widespread solution for runtime type checking.
As a JS dev it’s nice to see php imitate some newer js syntax like nullish coalescing, arrow function, … helps me to switch between the languages.
It really needs a way to declare type of small data structures though, in a very concise way (no class boilerplate, for performance eg. going through 10000’s of entities).
PS : on the other hand I’m starting to dislike how languages become "designed by committee", and lose the purity of the original design.( thinking of JS mostly here with its gazillion rfcs)
Perhaps worth noting - nullish coalescing is an old feature of the Unix shell. (From a quick skim through Wikipedia, it seems to have been added to `sh` in System III - released in 1981.)
As a very long time PHP developer I say this with love, because for PHP it's actually a blessing to be moving away from the "purity" of the original "design".
Enums with methods are essentially a compiler supported way of having several static readonly instances on a class with a private constructor. It’s not always useful, but it can be nice, sometimes. I’ve had a few times working with C# where I’d have liked those.
> Union Types - Combine several types into one union, which means that whatever input must match one of the given types: `function find(int|string $id)`
TypeScript and PHP have the distinct honor of being a popular language with ad-hoc union types (not the concrete subclass/enums that other languages seem to think are sufficient).
It commonly refers to PHP 7+ paired with clean code practices and SOLID principles.
The opposite is PHP5-style code from the early 2000s, no package management, no type strictness, no object orientation, just a giant spaghetti mix of JS, HTML, SQL and PHP in a 10kloc file.
Having used PHP since version 4 (20 years ago), I can say with confidence that its had its peak. Everything new added since 7.4 is just fluff or bloat. Fixing long standing bugs and performance improvements is fine, of course. But everything new they introduce adds to the pile of warts that's PHP. I highly regard those that try to improve it, but with the current direction it'll remain the colloquial example of how not to design a programming language.
I found that php8 has brought numerous features that will formalize things I am currently doing as hacks and workarounds.
Exceptions as expressions--I can stop writing,
`$x = $context['x'] ?? ThrowWrapper::missingValue('x');`
Named Arguments -- I use a hacky diy `Reflection` heavy version of this for an RMI/dispatch where json key-vals mapped to function params.
Static return type and union types -- I have been relying on PhpStorm docstring hacks for this sort of type-hinting.
`readonly` will be very helpful to express performant, immutable classes. I have a number of classes that are immutable-by-convention, trusting the caller not to monkey with the internals. (The idiomatic way to do this, `$immutable->getAttr()` is too costly in tight loops compared to `$immutable->attr`)
PHP still has lots of warts (function calls why you so aspensive?!?!?) but I keep being pleasantly surprised by how good of a tool it's evolving into.
Thank you. I don't need any of those, though. $immutable->getAttr() is easy to mock, easy to override, and allows for custom behavior (e.g. return clone $this->Attr).
Static return type, useful but since I use interfaces for everything it's not really needed. Union types, also not really needed because either 2 interfaces share a common ancestor or I'll have separate methods for different types. But most of the time, I encapsulate things behind interfaces that do one thing, so having different methods per type can often be avoided.
Named arguments are a pain for me since now I can't change parameter names anymore. This is particularly annoying with different coding styles in dependencies vs my own code. My code ends up not conforming to the coding standard that I've used since it was introduced (PSR-2R).
Exceptions as expressions is a nice to have, but exceptions in general are a thing to avoid doing. Not that things can't go wrong, not that chugging along in the face of errors is good, of course it's not. But if you have a lot of exceptions in your code, that's a smell of bad design. I've got 13 different exceptions used 20 times in total, over 4683 LoC on my current project. Mostly, whenever one of them is triggered, whatever I changed last was incomplete and led to an inconsistent configuration.
That said, your use case for PHP is probably very different. Especially since I don't care much at all about performance anymore. I used to, but CPUs are so much faster nowadays and PHP itself has improved.
I'm not sure the spread operator [or any form of apply()] is a good idea in a programming language. You've just added another bit of indirection that isn't even explicit, but is based on whatever the runtime state is. This is anathema to any sort of structured programming. The inferred state is just hand waved because any mismatch is pushed, as an incidental side effect, into the next function.
PHP has come a really long way, I really hope to see it's resurgence some day after everyone has been burned enough from running JavaScript as their server.