PHP has a strange identity problem. For a language that most would agree is used due to past popularity, it has a lot of breaking changes. But while syntax gets deprecated and function signatures changed, the stdlib is still a mess. The original randomly long functions are still there with no replacement in sight. To make my point, there's still no reasonable int parsing function!
I'm not against change, but PHP devs should decide if they want to make code maintenance easier, or make PHP an actually good language. Right now, it's in a weird in-between state. I'm not a fan of coming across old PHP code and having to make a bunch of small changes to port it to supported PHP.
Well, they basically took the __looks__ of Perl and bolted on a dynamically typed Java on top of it. I don't think there are languages more different in concepts and values than Perl and Java, and PHP is the result of that unholy mixture. Perl is crazy, but it has a very precise logic behind the madness. Java is boring and predictable. PHP is crazy while being completely random.
This is a good summary of PHP in the past and maybe the present. I think the PHP 10 years from now won’t have the craziness anymore, based on the current trend.
They've gotten more aggressive lately in wiping away the dusty corners of the language, little-used alternative syntaxes like these,some of the footguns. But nothing even approaching a full reorg/rename of the stdlib.
I think the sense is doing something like that would get you into an undesirable "Python 3" type scenario. Instead, the sort of unceasing wave of deprecations leads to some make-work but doesn't seem to cause the same kind of long term resistance to updating.
> But nothing even approaching a full reorg/rename of the stdlib.
It's been a long tradition in the PHP world to keep the PHP side of a module somewhat consistent with the underlying C API that the module exposes.
On the one side, people with a C background immediately find themselves at home in PHP - on the other side, "new" programmers coming from the Java, Go or the matured JS world are confused because of all the inconsistencies.
> there’s still no reasonable int parsing function!
Well, I suppose it depends on how one defines “reasonable”, and perhaps how one defines “parsing” (e.g., what is it you’re trying to do). As a comment elsewhere observed, while
(int)$val;
will force a non-integer $val to be 0, if what you’re trying to do is determine whether $val is a string literal that represents an integer, you can use
filter($val, FILTER_VALIDATE_INT);
instead. That will return the integer if it is, and false (actual boolean false) if it isn’t.
Is this the best way to do it? Probably not. But I think I’m okay with testing that filter in an if statement rather than wrapping the type casting in a try/catch block.
However:
> I'm not against change, but PHP devs should decide if they want to make code maintenance easier, or make PHP an actually good language. Right now, it's in a weird in-between state. I'm not a fan of coming across old PHP code and having to make a bunch of small changes to port it to supported PHP.
If the dichotomy you pose in the first part is correct, then “coming across old PHP code and having to make small changes” is unavoidable if they’re striving for the latter. Given that they’re clearly not down for making radical changes that break everything everywhere all at once, then it’s going to be in a “weird in-between state” for years, isn’t it?
stdlib will never change, because it would break every PHP project out there. Many of the previous deprecations as been relatively easy to handle, like switch from each to foreach, or make sure that you don't pass null to stdlib functions, but changing the stdlib itself would instead be a complete nightmare.
Remember that many projects out there needs to support multiple PHP versions at the same time, it would be extremely confusing if the stdlib started to do subtle changes between versions and also hard to properly handle and detect.
Like if you would swap $needle and $haystack for strpos(), it would be nightmarish to statically detect in an existing code base which is the correct order and quite hard for a human.
Introducing aliases is also a bad idea, there already exists aliases in the stdlib and they only add confusion when reading code, that would be true for new aliases as well.
Named arguments alleviates the problem with argument order in exchange for more verbosity.
What PHP could do is to introduce primitive objects, e.g. $str->substr(...), however that would not guarantee a well designed standard library either, because RFC:s and emails is not a good forum for designing API:s.
I think the correct solution is to implement operator overloading and let the community design a standard library/libraries. Because of the massive performance improvements of PHP the standard library is no longer required to be pure C, it can either be implemented in PHP or wrap the existing stdlib.
Yeah, PHP sometimes pretends it's a C derivative. I think it's a stupid idea most of the time, especially with regard to strings. C string handling isn't anything scripting languages should copy.
Besides, PHP now has its own (partly duplicate) class-based stdlib for some things, why not be consistent and "replace" all of the old stdlib?
> C string handling isn't anything scripting languages should copy.
Or C-like imports, it's ridiculous tbh, inlcude, inlcude_once, require, require_once.
My understanding is that PHP started as a basic templating language, a way to embed c function calls as tags in HTML.
In that way it's ingenious, people keep reinventing it with JSX, filesystem routing etc. Right now I'm thinking PHP should've gone the other way. Instead of adopting features to resemble other general purpose languages (things like classes from java and so on) it should've doubled down on web stuff, like JSX - in the sense of having a nice syntax for partials/components, eg <php-component props /> instead of <?php echo php_component(props) ?> and other comfort features, to become a platform.
You can kind of get this to happen in 8 and up: Doing math on a non numeric string is then a catchable TypeError so you can do 'x' + 0 in a try.
Doesn't avoid other PHP numeric-string stuff like scientific notation and floats being accepted, though. Passing to a int-typehinted function param in 8.1 gets you closer (will complain about float strings) but is currently just a annoying-to-work-with deprecation notice. Presumably it will eventually also be a TypeError.
We could debate that for a long time, but my point was different: There's no sane function in today's PHP that parses ints and handles errors (defaulting to 0 doesn't count).
/**
* Cast to int, fail if not a valid integer
* @throws \UnexpectedValueException
* @param mixed $thing
* @return int
*/
function as_int($thing): int
{
if (!filter_var($thing, \FILTER_VALIDATE_INT))
throw new \UnexpectedValueException("Value is not an integer.");
return (int)$thing;
}
While, yeah, it'd be nice if there were something like this built in... it's a couple lines of code. If that's your major complaint, I'd be happy to whip up a whole suite of proper functions to cast to primitives while throwing errors on invalid values since it's just swapping FILTER_VALIDATE_INT for the various types.
I think this illustrates my problem with PHP well: There are ways to do common tasks properly, but they're often hidden, obscure or basically require creating your own "stdlib extension", as seen here (I only heard about filter_var from this discussion, and I specifically searched for string conversion functions).
Your function proves my point: It looks correct, but actually breaks for as_int("0"), since filter_var with FILTER_VALIDATE_INT doesn't acutally validate the int, but parse it, and zero is falsy.
Above usage of filter_var is wrong, there is no need to cast $thing to int, filter_var already returns the filtered int or false on failure. The correct usage is therefore
/**
* Cast to int, fail if not a valid integer
* @throws \UnexpectedValueException
* @param mixed $thing
* @return int
*/
function as_int($thing): int
{
$int = filter_var($thing, \FILTER_VALIDATE_INT);
if ($int === false) {
throw new \UnexpectedValueException("Value is not an integer.");
}
return $int;
}
Thus the critique against PHP that is lacks a proper integer parsing function is simply not true, filter_var has been part of PHP since 5.2 released in 2006, over 16 years ago. filter_var works as advertised, because I use it almost every time i write PHP and that is to mostly to parse integers but sometimes also for other types. And I don't even wrap it with my own as_int function, using it inline with an simple if-check afterwards is actually cleaner. And if you prefer that filter_var returns null on failure instead of false you can simply add FILTER_NULL_ON_FAILURE as the third argument to filter_var.
And this is the recurring thing with PHP critique, vast majority of the time it just in imagination because nobody bothers to look it up.
> And this is the recurring thing with PHP critique, vast majority of the time it just in imagination because nobody bothers to look it up.
I see this from the other side: Good languages guide programmers toward good solutions. Criticism of the simplest or obvious solution is valid, because the language determines what that solution is.
Conversely, arguing that it's possible to write good code is largely meaningless. It doesn't mean that the language is good, just that it isn't completely unfit for purpose. Just look at the number of people who commented about other int parsing methods: Are they bad programmers, because they didn't know to look for filter_var when parsing ints, or is PHP a bad language because something so simple is hard to find a solution for?
Why so many failed to answer this questions is probably due to multiple reasons, here are a few
1) Some programmers are just either too lazy or too arrogant to read the manual, thus bad programmers. As a senior programmer that has helped numerous juniors in their work, this is probably one of the most common mistakes I see, they write code without checking how the API works, or they ask me why something isn't working when it can be easily found in the manual. This is not specific to PHP and I have seen this in everything from PHP to C++.
2) PHP is dynamic language, similar to JavaScript, types were not something you historically bothered with, thus parsing to int is not something the community has a large shared knowledge about, similar how it is rare in JavaScript. However with the introduction of primitive type hinting it has become more common to do proper parsing, hopefully PHP programmers will learn eventually. Thus it is a thing with dynamic languages, not specific to PHP.
3) Why can't programmers find the filter_var method in the manual and/or in the standard library? This I considered as valid criticism of PHP, the standard library is not structured because of the C like flat structure and many of the stdlib functions are weirdly named, like filter_var, what is filter to begin with?
The solution is to build a better stdlib, not throw out the language. I think the community can build a well designed stdlib if PHP implements operator overloading. The performance issues is no longer valid, PHP 7+ has great performance, thus worrying about losing important cycles is not really true anymore.
PHP as a language works well to build good solutions, I have done so in many projects. The critique here evolves around the stdlib, that is not something new.
The stdlib is part of the language, and while theoretically someone could take PHP and pair it with a new standard library, they could also take the PHP VM and pair it with a new syntax and parser with not much more effort. Just as its standard library is one of Python's biggest strengths and almost lacking one is one of JavaScript's biggest faults. Even if a community project is created to replace PHP's stdlib and offer a better alternative, unless everyone adopts it, it will always be just a niche alternative.
PHP needs to actually have a good standard library in its default distribution. Maybe looking to large frameworks like Symfony to develop one isn't a bad idea, but they've largely left the stdlib alone, so just waiting for them to start developing a complete replacement isn't going to work.
(For all its faults, JS' parseInt function is perfectly serviceable, but that's beside the point.)
My proposal would be to let the community build a stdlib and after it is battle tested merge it with core PHP.
It has been proposed before to have PHP source shipped with PHP (and also the possibility mix C and PHP) and think that would be the best option.
One option could be to have slower evolved stdlib in core and a faster community version with composer.
Reason why I’m proposing to develop it outside of core is because a rfc based process is not necessarily the best approach to design a good & well functioning api (and empirically that is true).
It is better to deliver a complete stdlib (or major sub parts) as one or multiple rfc.
And by doing like this you allocate resources better, the few with knowledge about PHP internals can keep focusing on that while the community, a much larger group, can design a stdlib.
And PHP has done a lot of great work on making user land and stdlib on equal footing, so now you can implement strpos(…) to exactly match the stdlib version thanks to union types, similar argument parsing and using same type rules (type errors) between the too.
Only major thing I know of that differs when exposing an api, that is either from a PHP C extension or PHP code, is operator overloading.
A rfc proposal to add it was unfortunate declined, but I’m hopeful that on day it will be added in some form because of this reason, it ought to be possible to express the same intent regardless if it is from C or PHP.
With user land operator overloading we can implement object based primitives with methods instead of the current function based approach. And it could be possible to extend it.
Other nice things you could do is to implement safe and unsafe string handling to avoid injections.
With operator overloading the community can evolve the language without the need to evolve PHP itself.
But the forced cast to integer is always guaranteed to result in an integer. So why would it make more sense to explicitly force cast a variable's type to an integer and get a boolean as the functions return value?
Edit:
> (int)$val === false
Would always be false because comparing two types, an integer and boolean would always be false.
I'm not against change, but PHP devs should decide if they want to make code maintenance easier, or make PHP an actually good language. Right now, it's in a weird in-between state. I'm not a fan of coming across old PHP code and having to make a bunch of small changes to port it to supported PHP.