Hacker News new | past | comments | ask | show | jobs | submit login
These are things in PHP which make me sad (phpsadness.com)
243 points by johnkary on May 27, 2011 | hide | past | web | favorite | 212 comments

What makes ME sad is no keyword arguments. Helper/wrapper functions either get an annoying and difficult-to-grok-at-glance associative-array for it's params (bad), or a huge list of rarely-used parameters (worse), or a huge set of wrapper functions to set their own paramters (even worse), or outright duplicated functions for similar-but-not-quite tasks (worst).

This happens to me while producing something like a jqGrid, or other javascript/html hybrid stuff that need a few extra options sometimes.

Django/Python? No problem! Just use the keywords you need.

(More Info: The difference between a single associative param standing in for keywords arguments, or a huge list of regular arguments is a choice in complexity/readability IN the function vs. calling it.

For the single dictionary approach, you lost the built-in parameter defaults nicety, which means you need to handle the case of a missing parameter manually. This kind of sucks, especially if you hate seeing PHP Notices during development (which kill JSON/XML output anyway). This makes your function often twice as big (or more) than it needs to be.

For the other approach, you wind up with calling

  foo("","","","real value", true, true, 2, false, false, "option I want");*
which just about invites all sorts of hard-to-find bugs, and you have to look at the function definition every time you want to change an option. Also, it's flat-out rude if you aren't the one calling the function.)

compact() + extract() is the closest you get.

  $foo = 123;
  $bar = getSomeBar();

  myFunction(compact('foo', 'bar'));

  function myFunction($kwargs) {
    if ($foo > 5) {

If you want to `sanitize' which arguments can be passed that way, use extract(array_intersect_key($allowed, $kwargs)); ((EDIT: or use EXTR_IF_EXISTS)).

Nb., extract() works on any associative array, you don't have to use compact().

Why would this be any better than just passing in a map of the parameters as the sole parameter?

  myFunction($parms=array()) {
  $parms = array('foo' => 'bar',
                 'baz' => 'yaz');

Concise. Documented, standard and configurable handling of existing variables (may be used for default values etc.) via EXTR_OVERWRITE, EXTR_SKIP, etc. Documented, standard behavior of compact() in regard to missing variables. No manual associating of foo with $foo -- less places for mundane errors.

Oh, and there's even that EXTR_IF_EXISTS -- so my silly idea to sanitize with array_intersect_keys() was totally unneeded. Make it

  $foo = 123;
  $bar = getSomeBar();
  $coot = 'boot';
  myFunc(compact('foo', 'bar', 'coot'));

  function myFunc($kwargs) {
    $foo = 1;
    $bar = 'xyz';
    extract($kwargs, EXTR_IF_EXISTS); /* sanitization: $coot will NOT get extracted 
        because the function doesn't expect / support that argument */

In case you weren't sure on this, it is exactly the same. Compact takes a list of variables names in the local scope and returns an associative array containing their values.

You can use the @ symbol to suppress errors when you're aware that the variable may be empty and you've considered the possible effects. When I used to write PHP, I'd often write something like

There are ways to suppress PHP notices without just turning off the E_NOTICE output.

It shouldn't be ok to write code that is known to throw an error, and handle it by suppressing that error. Silently failing code is just a bug waiting to happen.

It's also making the interpreter do unnecessary error handling work when a simple "if ($_GET['foobar'])" would suffice.

It should be ok (the poor PHP implementation aside). Auto-vivification is something that's very useful in Perl and I miss it greatly in the languages I program in now. Being able to do this:

    $one->{ two }->{ three } = [ $four ]
Without having to check every link for definedness makes for cleaner code, IMO. Making it optional "suppressing that error" would be a good middle-ground.

Coffeescipt has the existential operator, not quite on a par with Perl's autovivification, which allows:

    zip = lottery.drawWinner?().address?.zipcode

The Coffeescript ? operator is certainly quite handy. I suppose it's explicit nature is what helps, as information on the error you're trying to mask is built into the syntax. With @ in PHP however, you simply don't know what it's trying to stop, and what undesirable affects it may cause, which I think is the main objection to it.

It's inefficient to do that, as from what I understand PHP actually sets the error level to none, processes that line, sets it back, and continues. Also it would suppress any other warnings from that line, which could be unrelated to the supplied argument value.

Instead, I use a 'get or else' function, as in some functional languages. For arrays, it goes

    function get_or_else($array,$key,$default=null)
       { return isset($array[$key]) ? $array[$key] : $default; }
This avoids any warnings, and also allows you to specify a default.

I wasn't aware of that implementation detail. Hey, now I respect PHP even less than I did before.

Your solution makes for some good boilerplate, but things like that are exactly why I use Python for everything it makes sense for: these things are baked into the language (in Python it would be array.get(key, default) ).

Yeah, it's part of Scala's type system, too - (Option, and Some or None. Better language designers go to great lengths to make simple things like null values well covered). Python will throw a fatal error and exits on reference to a nonexistent Dictionary key, but PHP blithely fills in the value with something falsy and continues.

I'd rather be using Python too, but for some apps we have to work with a lot of PHP legacy code, so I do what I can.

To be fair, Python doesn't throw a fatal error. It throws an Exception, which most people know to handle. The idiom is use a try/except block, but if you're clever you can usually avoid the need.

Scala borrows the option types from SML (or, at least, SML has them and is much older). I love SML for its strict semantics (if something passes through the type system it most likely works as expected), but sadly design really doesn't inform platform choice (case in point: C++ is still common. I don't hate it as much as some people do, but it can't be said to be particularly well designed).

Hey, in case you are interested I constructed a reply to your post here: http://commonphp.blogspot.com/2011/05/keyword-functions-in-p...

In a nut shell though it's essentially a write up of my library which allows for creating keyword function wrappers so you can do stuff like:

       needle, 'peter', 
       haystack, 'is peter in here?'

Isn't a wrapper function the solution to this? Or even... a wrapper function that takes an associative array of options as an argument.

There's a lot of valid points there, but "#33 Cannot override private methods with a subclass" is the right behavior. That's exactly what private is for, and it's important to know that such names are non-colliding and you can rely on their implementation.

Use protected for overridable methods. You shouldn't mock or directly test private methods in unit tests — they're not part of the interface!

public/protected/private is a dumb idea in dynamic languages. If you don't want someone calling your method, prefix it with an underscore and say "the results are undefined if you call methods that start with an underscore". Done. Easier to maintain, easier to test, less code to type in.

Come to think of it... public/protected/private is a dumb idea in C++ and Java, too.

> public/protected/private is a dumb idea in dynamic languages.

PHP is mostly a static language; it has more in common with Java than with say Ruby.

> prefix it with an underscore

Oh god, really. Next you'll be telling us we don't need namespaces, we can just use an underscore as a separator!

> and say "the results are undefined if you call methods that start with an underscore". Done. Easier to maintain, easier to test, less code to type in.

Or you could just build that all into the language itself so it's self documenting and provides a nice concise error message when used incorrectly!

I'm amazed that people would argue for naming conventions over actual features. Hell, nobody is saying you have have to use it; if you'd rather use underscores the languages will let you.

"PHP is mostly a static language; it has more in common with Java than with say Ruby."

Can you expand on that point a bit? I see PHP as far more similar to Ruby than Java when it comes to dynamic vs static.

A few things about PHP, Java, and Ruby: PHP, Java, and Ruby are all compiled to byte code before executed. Java and Ruby are strongly typed languages. PHP and Ruby are dynamically typed languages (no explicit variable declarations). Ruby and PHP are compiled when run but Java is compiled ahead of time.

But significant to my point: Ruby classes are created at runtime but PHP and Java classes are created at compile time. This is why you can't, with runtime code, alter the structure of a class in PHP or Java.

Your point about class definitions being frozen is apt — but much of the nomenclature you're using to describe languages is meaningless.

Please read the classic What To Know Before Debating Type Systems: http://cdsmith.wordpress.com/2011/01/09/an-old-article-i-wro...

Not meaningless, just debated. And even then, the web has helped to reduce the confusion around the terms.


That article you linked to is useless. If we just called them alpha, beta, gamma, and delta type systems would a rose by any other name smell sweet?

No kidding, I hate having to write some reflection BS in C# just to call a 'private method' as if addresses in memory cared about such things. The worst is some of the MS extensions for WIN32 that have private constructors designed to prevent obvious functionality. (Basically the constructors are private for political reasons). IIRC, it was something to do with reading COM streams from .msg files. It really ticked me off.

I don't see how dynamic languages make it dumb.

Dynamic or not, objects have interfaces and this is a way of defining the public interface and catching violations of it.

> Easier to maintain, easier to test, less code to type in

My impression is opposite. They add friction to changing visibility. I like to start with everything private and then unprotect as needed.

It's extra character to type and it interferes with autocomplete.

Accessibility of "private" methods shouldn't be help in tests — you'll end up creating tests that depend on implementation. If class is too impenetrable to test, then refactor it (split concerns, add dependency injection, etc.), don't unprotect it.

Recently at my company we're writing a lot of JS and its' lack of "public/protected/private" doesn't make it easier to maintain or test. Actually, it's quite frustrating because you know you can't test it properly - everything public? it's a ticking timebomb, someone at some point will simply override your method somewhere and hell will broke loose

Even though JS doesn't have language constructs for public/private, there are a number of different ways to write modules with hidden members by use of closures.

Crockford explains with some examples here:


I'd say that using closures and functions to create public apis with internal private structure does qualify it to have 'language constructs for public/private'.

It just took programmers collectively over 10 years to figure it out. I blame the 'new' keyword in JS, it feels completely grafted on after the fact.

Lua has been using this method of designing modular programs for years.

I know you can do it, but it produces quite an overhead and it's ugly. But that's for another discussion ("sad things in JS" maybe) - here my main point was that, no, public/protected/private is not a dumb idea in dynamic languages.

I wrote a simple library based off of Crockford's writings to make creating reusable constructor functions that supported public/protected/private simple (and without resorting to silly "if it's preceded with an underscore don't touch it!" business). It was written mainly with Node.js in mind, but you could strip out the CommonJS package stuff and use it that way.


Agreed. When I started using python I thought that I would miss protected/public methods, but I was wrong. Conventions are the better solution and make testing incredibly easier.

Totally agree. Of course, because PHP has the public/protected/private idea, it's correct in not redefining those for its own meaning, so the complaint is missing the point.

I think the worst villains of the public/protected/private family are getter/setter methods, it bugs me when I see them in Python code. We use enunciate ( http://enunciate.codehaus.org ) at work, and we bundle AMF endpoints with our stuff. Unfortunately the Java-to-actionscript step complained when our data objects don't have getters/setters (since I like just using public attributes), so now I have two Python scripts: one generating the Java code for a data object along with annotations, the other adding getter/setter methods.

"#41 Cannot create a final abstract class" is borderline too

I like to think that declaring a class as "final" is simply a lack of imagination.

Yup, wouldn't a final class with a private constructor be more appropriate there?

Indeed. In 5.3 you could have regular functions in a namespace, so there's no need to abuse class for that any more.

Other than that it smells like a variation of the singleton antipattern.

Before everyone goes all "why don't you switch to language X or platform Y or lisp variant Z" I just want to say good job on this.

These all seem to be sane critiques of PHP without being all doomsday world-ending inflamatory. Kudos.

Also, I think that this is another example of how hard it is to build up a large and widely-used language/framework without having lots of warts. Especially since PHP wasn't originally designed with the intention of powering everything from a simple blog/cms to facebook.

yeah.. php really has gotten a bad rap.. nearing ASP proportions

By ASP you mean VBScript, right? Because ASP pages can be written in JScript as well, and I remember JScript was quite nice.

I've definitely run into #1 on the list. "Paamayim Nekudotayim" is a transliterated version of פעמיים נקודתיים‎, which means "double colon" in Hebrew. Zeev and Andi are Israeli, which kind of explains it, but the error message is still pretty useless.

Of all these complaints, I’m most forgiving of the name of T_PAAMAYIM_NEKUDOTAYIM. You only need to look it up once; the cost is a few seconds of Googling and the payoff is you learn a fun random fact. It gives the language a bit of color.

Still, glad I’m not doing much PHP anymore.

Actually, I kind of like the feeling that I'm building a golem when working on webapps.

This should disappear soon[1], it seems the patch has been accepted (or is on a good way to be), according the internals@ mailing list[2].

[1] https://wiki.php.net/rfc/improved-parser-error-message

[2] http://news.php.net/php.internals/52436

I'm actually surprised it's still there. I remember WTFing at that about four years ago.

I think pretty much every single PHP developers feels like you ^^.

Even in Hebrew, that is a useless error message...token names should mean what the token means, not what it looks like.

Presumably, the tokenizer doesn't know anything about the meaning of the tokens it's extracting. It's the parser's job to attach meaning to tokens.

Presumably, the programmers should pick reasonable token names for the sake of other programmers.

They're all just numbers to the tokenizer...

For unexpected token I think what it looks like is more valuable. Unfortunately most English PHP developers don't speak Hebrew. =\

I'm actually quite fond of that particular quirk. At least it's easy to search for!

> the error message is still pretty useless.

not at all. A google search for "Paamayim Nekudotayim" gives you thousands of pages relating to exactly the error you're experiencing. It's WAY more useful than "Illegal operation" or "Syntax error".

  > It's WAY more useful than "Illegal operation" or "Syntax error".

"Syntax error on line 14" -- Okay, time to look at line 14 for a mistyped semicolon or something. These two words Mean Something.

"Unexpected T_PAAMAYIM_NEKUDOTAYIM on line 14" -- means absolutely nothing unless you've already looked it up. It's essentially easily-googleable nonsense. It might as well say "Error 0x444F808E". You can google that, too, and it also tells you nothing useful.

You would prefer, when encountering an incorrectly used double colon operator, PHP said "Syntax error"? Even when I'm directed to look only at the surrounds of the double colon, it has been difficult to understand the problem in some cases... it looks like valid syntax. Now, you might say that this is a problem with PHP's syntax, and I have no defense against that, but rolling this into "invalid syntax" with no further explanation would cause no end of trouble for those new to OO in PHP.

Uh, how about "Double colon error" ?

Right, because there are thousands of people going to ask on mailing lists WTF that means. Given the small fraction of developers worldwide who speak Yiddish or Hebrew or whatever, 'double colon' might be a better phrase to use.

I still prefer something like "illegal scope operator"

Its only a "bug" because there's an unspoken rule that all programming languages should be written in English, and English doesn't have a proper word for this symbol.

Pretend that English had no representation of an ellipsis, but Hebrew did. Should the language author say "Expected: dot-dot-dot" in the error message to appease native English speakers, or should (s)he use the unambiguous form?

It's not an unspoken rule, it's an established convention.

This isn't about whether we use English or not, or whether that's the right choice or not, it's about consistency. If you want to create a language that has all-Hebrew tokens and error messages, knock yourself out. Just do it consistently.

In this case, the Hebrew word literally is T_DOUBLE_COLON, so not much is gained by its use. Perhaps reporting an "unexpected scope resolution operator" error would be better.

Or, even better:

"Unexpected '::' on line 14."

I wouldn't want to see "Unexpected key/value delimiter" (=>) or "Unexpected opening of new scope" ({). Just show the character(s) you found you weren't expecting.

The rest of PHP is in English. A language should be consistant with itself.

OK, let's pretend that. Then, we have someone designing a programming language with English keywords that uses a token for which English does not have a name (not merely a well-known name, not even an obscure one, but no name at all)

IMO, that would only be a good idea when taking part in a obfuscated programming language context.

Pretend that English had no representation of an ellipsis, but Hebrew did. Should the language author say "Expected: dot-dot-dot"

Yes. It's not about appeasement, it's about consistency.

The ridiculously terrible behavior of == is what makes me the saddest.


We then have === which does what == is really supposed to do, but even that still sometimes does the Wrong Thing.

The way I've explained this (braindead) behaviour to people is that == is the 'equivalence' operator, and === is the 'equality' operator.

This sort of 'well, close enough' behaviour has bitten me in the past as well. While writing a JSON bridge between an older PHP backend system and a newer Rails frontend, we kept getting exceptions on the Rails end.

It turns out that the JSON library uses isnumeric() to determine if a value is a number or not - which makes sense, in some respects. The problem is that we had a parameter (the external vendor's product SKU) which was a string that, in some cases, consisted entirely of digits. On those few occasions, the JSON library would say 'Oh, this is a number' and encode it as such in the JSON.

When Rails tried to unpack it, we got an exception because our Rails model was validating the data on the remote end and choked on getting an integer instead of a string.

We ended up having to actually modify the JSON library we were using (everything else we tried either didn't work or had the same bug) to modify the check. Completely ridiculous.

Except when you're comparing objects!

I want to make sure that object A and object B are instances of the same class. Also, I want to make sure that they are equal i.e. that every attribute is equal. Also, since I'm now used to always using === instead of == for such comparisons, I use === to make the comparison. I would think that == would perform an == comparison on every attribute, whereas === would perform an === comparison on every attribute.

Nope! Using === actually verifies that the A and B are in fact references to the same object in memory, just like the "is" operator in Python. Got me again, PHP! How do I do my === comparison? Manually, that's how!

Object equality is non-trivial matter and subjective. Java delegates the consideration of object equality to Object.equals(), intended to be implemented by yourself as required.

That PHP chooses not to try and provide a means of determining object equality is not a poor choice. Using the === operator to test whether two variables are references to the same object is then also not a poor choice.

Wow, a downvote within 30 seconds of posting?

"php" == 0 returns true, and this makes sense how?

It doesn't make sense unless you understand how PHP works - at which point you'd use ===.

> It doesn't make sense unless you understand how PHP works ...

In other words: equality is not intuitive. Awesome!


Let's take a look at "how PHP works":

  0 == 08 // true!
WTF, really? Well, let's just use the magical 'I-mean-actual-equality-not-some-other-kind-of-equality' operator:

  0 === 08 // also true!

  (Sonofabitch/Facepalm) * Infinity
Of all the areas of a language in which one could gain expertise in, I think testing equality should not be one of the more difficult to master.

This is just stupid behavior. 08 is an invalid octal sequence, but no error is raised. You can't detect this condition unless you do your own pre-parsing before allowing PHP to try to parse it!

That's the grammar for PHP integer literals[1]:

    decimal     : [1-9][0-9]*
                | 0
    hexadecimal : 0[xX][0-9a-fA-F]+
    octal       : 0[0-7]+
    integer     : [+-]?decimal
                | [+-]?hexadecimal
                | [+-]?octal
"08" and "09" do not match any of these.

    php -r "var_dump(08);"
Yields "int(0)", while the case should rather be treated as a syntax error, if you ask me.

The bottom line probably is that your literals just shouldn't have leading zeroes…

[1] http://www.php.net/manual/en/language.types.integer.php

I've been programming in PHP for a long time and I've never ever accidentally used an octal anywhere. Does such a non-problem really need this much attention?

Perhaps you ask a user to enter the month of their CC expiration date, which is shown as 08/14 on their card.

  $v = validated_integer($user_input); // the user input 08
  if($v == 0 || $v === 0) { // let's just be safe
    // the Wrong Thing happens
This is a contrived example, sure. But you've never checked to see if a user input the number 0? Or a non-zero, positive integer?

I'm not sure what you expect to happen there but the following code always produces "Correct!":

    $user_input = '08';
    $user_input = (integer)$user_input;
    if ($user_input == 8) echo 'Correct!';
    if ($user_input == 0) echo 'Incorrect!';
If you take out the cast, the result is the same. If you change the numbers to '010' and 10 respectively, the result is also "Correct!". There is no weirdness.

It makes sense for the same reason it makes sense in Perl: use a string as a number and you get the number that is at the start of the string. E.g., "12" == 12, and "12php" == 12.

But Perl has both "eq" and "==". PHP doesn't.

Perl recognises that it is a bad practice.

  perl -we ' print "true\n" if "12" == "12php"'
  Argument "12php" isn't numeric in numeric eq (==) at -e line 1.

  perl -w -e 'my $foo = "12php"; $foo = $foo + 1; print $foo, "\n";'
  Argument "12php" isn't numeric in addition (+) at -e line 1.
(an exception seems to be made for $foo++ though... that's Perl for you).

$foo++ isn't an exception. It has documented behavior on strings. That is sometimes very useful.

I meant it's an exception because it does not throw a warning, even though you are treating a string as a number. (This is contrary to $foo = $foo + 1). The DWIM string auto-increment doesn't even kick in unless the variable matches /^[a-z]/i.

That does not make sence that just meens both languages suck.

Because the string is first converted to an integer.

"==" makes the comparison after converting types (see: Type Juggling in the docs) where "===" requires that the types be the same in order to be equal.

Kind of weird the first time you see it, but it's a language design choice and does make sense once you understand it.

I think the reason people object to this behavior, even when they do understand it is that it makes the obvious default (==) dangerous. It's especially dangerous in the hands of the sort of non-experts for whom it's intended to make life easier.

== really isn't that dangerous unless you use it dangerously. Comparing non-numeric strings to numbers is already odd.

But then it means that "==" is no longer transitive, which I see as very unnatural and confusing (even if the underlying reasoning sort-of makes sense).

What doesn't make sense is the rationale for designing it this way.

As usual, when one of these lists comes out about PHP there are some real issues, some non-issues, some have been fixed, and a few things that are just different. I'm surprised these sorts of posts keep getting voted up here; haven't we seen it all before?

I do a lot of PHP development but not exclusively and rarely does these sorts of deficiencies in PHP ultimately matter.

My favorite PHP design misfeature: what does the following code do?

  $foo = array("a", "b", "c");
  foreach ($foo as &$bar)
    echo $bar;
  echo "\n";
  foreach ($foo as $bar)
    echo $bar;
  echo "\n";
The "&" is a foreach-by-reference, for those not familiar with the language. When you think you've figured it out, you can execute the code at http://www.contrib.andrew.cmu.edu/~jwatzman/foreach.php

I filed that bug 7 years ago and they wouldn't fix it: http://bugs.php.net/29992

I had it a little wrong in the initial report, but it was cleared up in the comments. The reluctance to fix stuff like this because "people might use this for some weird reason" is one of the reasons I'm glad I don't write much PHP anymore.

It's not a bug though, it's how references work. The code is exactly right. You might not expect the output but that doesn't mean it's logically incorrect.

Yeah, I understand the cause. Just because those steps make logical sense doesn't mean it's not a bug.

My real point was about the WONTFIX tendencies of the PHP dev team at the time (I've been gone a while; maybe it's better now). It's absolutely the thing I miss least about that community. I mean, when I filed that bug PHP 5 -- the first version to support foreach with references -- was less than 2 months old. The "people might be relying on it" argument doesn't hold much weight with me today, but it certainly didn't hold any for a 2-month-old feature.

It's not a bug because it's not a bug. How would you propose they fix this non-bug anyway?

At the end of the first loop, $item contains a reference to the last item in the array. Just as $item would contain the value of the last item in the array if you weren't using references. In the next loop, $item still contains that reference so now you're overwriting the value of that reference. You can't assume the second loop knows anything about the first loop.

People might actually be relying on this behavior but not in the way that you're expressing here. References are not just assigned in foreach loops.

The fix for this is that foreach should create a new iterator variable which overwrites the existing one. That would preserve expected behavior.

I think you should pause for a minute and summarize all of the WTFs you've rationalized on this post. Just the volume of it makes me incredulous that you don't think PHP == FAIL (or perhaps === if you like).

> The fix for this is that foreach should create a new iterator variable which overwrites the existing one.

That would be very strange behavior though that has no equivalence in any other part of the language. I'm sure if it did that, somebody would put on the list of things that PHP does weirdly!

> That would preserve expected behavior.

I'm afraid the behavior it has is the expected behavior. The problem isn't the language in this case.

> Just the volume of it makes me incredulous that you don't think PHP == FAIL (or perhaps === if you like).

Clearly you haven't been paying attention to my posts. I might be rationalizing some of these sort of ridiculous ones but I certainly don't think PHP is full of win. I'm just pragmatic. These problems just aren't that bad.

> That would be very strange behavior though that has no equivalence in any other part of the language.

How is it strange? When you declare your iteration variable, it unsets any existing definition of that variable if there is one, before it inserts the new variable. Why would anyone enter a loop and expect the iteration variable to have a value defined outside the loop?

Moreover, even if someone can find a reason why -- why make define the language around a need to support such badly designed programs.

> I'm afraid the behavior it has is the expected behavior.

Fine. s/expected/intuitive/g

> The problem isn't the language in this case.

Agreed. It's the people who designed it.

> These problems just aren't that bad.

This is my point: the individual issues are all workable. The real problem is that the language is maintained by people who have no idea how to design a language, frankly.

> How is it strange? When you declare your iteration variable

You're not declaring anything; PHP doesn't have variable declarations. In this case, you're either creating a new variable or using an existing one -- just like everywhere else. But I'll concede the point. While the code is technically correct, unsetting the loop variable might be a nice addition. But I fully understand why they wouldn't want to make this change.

> Why would anyone enter a loop and expect the iteration variable to have a value defined outside the loop?

Thus us the takeaway point, I think. The loop would work perfectly fine if $bar was lexically scoped to the foreach, but it isn't. That's a general weakness in PHP compared to pretty much any other scripting language used today.

after the first loop is highly recommended.

I hate PHP, but this article isn't very good. It's strange that there is an "implications for the internals" reason. Guess what, you can just read the internals. It's open source.

The parser emits weird error messages because it is a very simple yacc grammar. (And because they turn off yacc's "produce better error messages" mode.) If you want good error messages, it's going to cost you -- just read perl's toke.c if you don't believe me. Good error messages cost a lot.

You can just read the internals, but that doesn't mean that the criticism is wrong. Certain problems do suggest deeper internal issues.

"Good error messages cost a lot" and "They turned off yacc's 'produce better error messages' mode" seem to contradict one another.

And no, in a lot of cases the parser emits weird error messages because the internal variables are named weird things. If you're telling me it's unreasonably difficult for PHP to produce a better error message than "Unexpected CONSTANT_NAME" than why name your constants unintuitively?

While it doesn't detract from the point of your post, the behavior of private is correct and intended. If you wish to override an internal method of a class in PHP, like Java, you must declare it protected, not private. This is the difference between private (completely internal, not inherited) and protected (internal, but inherited by subclasses).

I'd love to see similar lists for other languages. I've been coding in MATLAB as of late, for instance, and rediscovered my hatred for the fact that you can't index the output of a function without assigning to a temporary variable. For instance, `foo(args)(:)` causes an error. You have to use `X = foo(args); X(:)` instead. That makes me just as sad as some of these PHP sadnesses.

MATLAB does get one thing right: Function arguments are always passed by value. This "referential transparency" really makes it easier to reason about functions and test them.

It's the one thing I hate about SciPy.

Passing by reference for performance reasons should be automatically handled by the compiler. I.e., A=sort(A) should be handled in-place without requiring a new function sort!(A).

I'm not so sure I agree. Python in general is very consistent about pass-by-value versus pass-by-reference semantics, whereas MATLAB infers things in ways that are far from transparent. Look at, for instance, the way the `parfor` loop construct differentiates between "broadcast," "sliced" and other such variables, and how fragile that inference is. Maybe I haven't thought clearly enough about this particular issue, but I don't think of MATLAB as being transparent.

Yes. Though Matlab has gotten massively better in recent years. It's just that the defaults, for backwards compatibility are still The Wrong Thing (TM). Look at function handles, and cells for string handling.

That's called array dereferencing. It doesn't work in php either, you need to assign to a temporary variable. I've been following a patch in the works (at https://wiki.php.net/rfc/functionarraydereferencing ) but there doesn't seem to be much progress on it.

So how do I contact the author with updates?

I clicked on a random item - the complaint that explode() doesn't take the empty string and return an array of each letter. But of course you can just use the str_split() function to do that (which is way more logical than passing an empty string).

So how do I contact the author and reduce his sadness level?

Or is this one of those websites that don't want to remove items, even if they are wrong?

For an illustration how PHP is 'different' from other languages, consider 'implode':

implode — Join array elements with a string

string implode ( string $glue , array $pieces )


implode() can, for historical reasons, accept its parameters in either order.

WTF! What other library has a major function which doesn't care about the parameter order? It goes against every notion of good design.


PHP's single greatest advantage is ubiquity - would love to see a CoffeeScript compiler for PHP that smooths out these issues.

you could say that all other web platforms are blub because they don't see the value that PHP brings to the table.

a total idiot can install PHP and get a system that will meet the performance and reliability needs of 99.5 of web sites out there.

tomcat, mod_perl, the ten different ways people host Ruby sites and all that make a lot more trouble for you. I've run PHP-based web servers for hundreds of sites that have served billions and billions of hits over the years and never once had to restart Apache because an application server got lodged. read that again because if you skip it, you're sysadminning blub.

every other system requires that you make choices, and the truth about choices is that faced with a binary choice there are two common outcomes: (i) a person freezes up like a deer in the headlights or (ii) a person makes a random choice that they're 50% likely to get right. (i)'s probably the better option.

i can complain about things wrong with PHP forever and i've got plenty of reasons to get off the PHP train. however, if you want to kill PHP, it's not enough to attack what's wrong with PHP, you've got attack what's right with PHP... You've got to make a better PHP than PHP.

I won't defend PHP as a language, but from an accessibility point of view, other platforms could certainly make things easier.

Coming from a PHP background, the first time I tried Django, I was rather dismayed at the amount of set up involved. I think after following a few tutorials, I was able to more or less get a running mod_WSGI setup, though the only way I could seem to get the web site to refresh was by restarting Apache.

After I got over the fear of using an http daemon written in the same language as my web app, I discovered Ruby / Sinatra, which gave me more or less the same immediacy I was used to from PHP.

Even so, I doubt I could explain Heroku to a non-technical friend in the same way I could convey an understanding of uploading a php web page to a LAMP host. (Ubuntu's broken support for RubyGems didn't do much to help my migration from PHP either).

It seems to me that until Python and Ruby have an infrastructure that's as friendly to novices as PHP is, we'll be seeing the same "PHP ghetto" effect that we've been seeing for the past decade.

a total idiot can install PHP and get a system that will meet the performance and reliability needs of 99.5 of web sites out there.

This is like living in a house where the builders were "total idiots" and hammered in all the screws with a hammer instead of screwing them in with a screwdriver. Sure, it holds together. It might not even collapse in a light breeze.

But one day, you'll want to reshingle the roof, or there will be a thunderstorm, and then your house collapses, killing your entire family. Good engineering requires good implementation. PHP makes good implementations too hard.

every other system requires that you make choices, and the truth about choices is that faced with a binary choice there are two common outcomes: (i) a person freezes up like a deer in the headlights or (ii) a person makes a random choice that they're 50% likely to get right. (i)'s probably the better option.

Theoretically, this is why you hire people with experience. They picked randomly the first time, and then gathered data. Their random choice either worked or it didn't. Repeat a few times and you have "senior system administrator" and "senior engineer" instead of "random dumbass we found on the street corner", and then this part of the equation goes away.

Now, if your goal is to produce something that sometimes works with the least amount of money possible... yes, you should outsource your development and deployment to some high school kids in India. If your goal is to produce something that works...

(Also, the days of PHP's deployment superiority are nearly over. With mongrel2, I can restart my app instances without losing a single request!)

Also, the days of PHP's deployment superiority are nearly over.

So I've been hearing since 2000 or so, when I chose RXML/Pike over PHP because PHP was a complete mess. PHP has gotten considerably better since then; now it's only painfully messy, rather than unusable. Sometimes it seems like every competitor has been busy building castles in the sky full of magic and wonder -- as long as you want to do exactly what the creators of your framework wanted to do, and as long as you're willing to stop by and maintain your app. PHP is more of a fire-and-forget language for apps... you can write it and then ignore the app for years without worrying about memory leaks or crashes or that it's taking up resources on your virtual server...

With mongrel2, I can restart my app instances without losing a single request!

Wow, what an achievement! This is the one thing that PHP really, seriously got right: no application server. There are applications out there that need the extra efficiency of not starting up on every request, but the vast majority of webapps do not. The additional robustness and sanity provided by not having to wonder why your app server fails after 292744 requests, or what went wrong when it just stopped responding, or whether, indeed, you might lose requests when restarting -- that helps me sleep at night. Few webapp-oriented languages have this, preferring instead to try over and over to get the application server paradigm right, this time, for sure! We just have to add a little shim here, and build another layer over these layers to interface with that one...

> Wow, what an achievement! This is the one thing that PHP really, seriously got right: no application server.

I think you mean PHP has no 'apparent'. It damn well does have an application server, it's called mod_php embedded in Apache processes or php-fcgi backends.

The thing is, that PHP apps DO fail after a certain number of requests, it's just hidden from you. Internally PHP ships with a MAX_REQUESTS (which defaults to 1000 I believe), after a backend has served that many requests the process is recycled (an expensive and non-ideal operation on high load applications).

If you do a look around on Google you'll find this behaviour ships with PHP because of 'known memory leaks'. Rather than fix memory leaks the authors have opted to restart on an arbitrary number of requests. Does this sound like good design to you?

You think there's no application server because you've likely never worked on anything substantial enough to notice the silly string holding the whole mess together.

Well, if you're considering Apache+plugin to be an application server, then I guess I need to say: no additional application server other than the web server. Most modern systems have a web server and a separate process for the application server (proxied to over HTTP or fed by FastCGI or WSGI or a neat otherwise unused protocol). The standalone application server (back when I was mostly using those languages) always seemed to have a bunch of quirks and to fail at every insult. Compared to the Rube Goldberg nature of some of these stacks of servers and protocols, PHP is delightfully simple, conceptually.

> Compared to the Rube Goldberg nature of some of these stacks of servers and protocols, PHP is delightfully simple, conceptually.

I agree that what you could call it's deployment API (or whatnot), that it is very simple. I think the reason for it's success is it allowed HTML/CSS 'programmers' to progress to simple scripting within their existing deployment metaphor (upload via FTP, use a PHP file extension, wrap PHP in <?php tags).

However, there's no reason that you couldn't design a similar thing in say, Ruby or Python, where people upload files with a specific extention FTP and it runs some templating language (like ERB or Pythons equivalent). You'd need some web api to allow triggering reloads of files (or reloads on every request if the server is being used for development).

PHP out of the box re-parses _every single script on every single request_, which is what you'd expect a development environment to do, but 'in production' that's what PHP has always done.

Hence were born the optcode caches (which work rather well now), like APC. But still, on every request, every file that is required has a stat performed on it (you can turn this off, though).

It's all very lowest common denominator, and the high end stuff is severely lacking and poorly documented. It's possible to have the best of both worlds (well designed language, pragmatic libraries and toolset out of the box, simple deployment AND well defined high end high traffic considerations), but PHP ain't it.

However, PHP was designed from the outset to run in this mode so the interpreter is an order of magnitude faster than Perl, which is what competed with PHP back in 2001 -- PHP was ~designed~ through and through to do what it does, and that's why it does it so well.

I know I might get voted down for not adding to the discussion, but I loved this post. I actually LOL'd. Hammered in screws is exactly how PHP feels to me. And, as a long-time PHP dev who still has to use it on the job (but never for personal projects), putting up a defense of it screams "n00b" to me more than anything else.

It's one thing to justify its use on the grounds of supporting legacy systems, or other similar compromises. But if you actually think it's a good, well-designed language, then your metric of "goodness" vis-a-vis programming languages is uninformed.

and it pick mongrel 2 I have to evaluate a number of different products for hosting ruby, each of which claims to be way better than all the others... yeah right

"you could say that all other web platforms are blub because they don't see the value that PHP brings to the table."

I do not recall at any point in Beating the Averages [1] in which pg used "ease of installation" as part of the definition of a blub language.

Blub has a specific meaning. It's not a synonym for "bad".

There are plenty of other technologies that are as reliable as PHP. Ruby was not really one of them. Ruby went through a bad hype cycle a couple of years ago and was never quite as good as it was sold to be, especially on the reliability front. It's a great anecdote but a bad argument.

[1]: http://www.paulgraham.com/avg.html

You don't get it.

In my mind the important thing about "blub" is that there's a valuable feature a language has and the blubbers don't understand the valuable feature.

For instance, ALGOL-type languages use Chomsky's generative grammar to define a syntax that people find intuitive. LISP is blub because it rejects this major innovation.

Languages that are !PHP are blub because they don't recognize that "ease of installation" is a valuable feature.

Everybody understands PHP's ease of already-existing-installation is just about the only thing keeping it going. The idea that this is news is a strawman, I've seen this discussed for years and years.

The thing that makes it win though is not that PHP is intrinsically that much easier to install or run, what makes it win is that it comes pre-installed on most hosts. That's not a problem a language community can solve, that's a problem only the cheap web hosts can solve.

On one of my VPNs, I've had the experience where Django is actually easier to install, because all the mod_python and stuff was already in the distro, and it took less configuration than PHP to make it work and not be a menace to the net. PHP has a lot of really stupid things you better get right if you're trying to configure it from scratch, or you're insecure by default.

But, it didn't used to come pre-installed. On many hosts in the 1996-1998 range, Perl was the default, and sometimes only, option for dynamic apps. But typically you had to only put files in /cgi-bin, futz with permissions, remember to include content-headers, etc. PHP 'won' because it was genuinely more straightforward than the competition in most use cases.

A better PHP than PHP: You mean like Railo?


(Scroll to bottom where they address why for PHP devs)

that article is strikingly inarticulate. if you've got to tell me to scroll to the bottom, then it's a complete failure at selling railo, whatever it is

I am getting a 404 with the link right now. Railo is a JBOSS project that is an open source version of CFML. Here's what they say about Railo in comparison to PHP:

• Simplicity

More powerful tags for simple file, email, database and other common operations.

• Best Practices Support

If you want to build OO apps using TDD, you can do so. If not, you can still hack out working scripts in minutes.

• Frameworks

A wide range of frameworks designed to make it quick and easy to build well designed web applications.

• OSS Projects

RIAForge has hundred of pre-built projects so you can quickly deliver anything from a blog to a content management system.

• Robust deployment

Railo CFML is easy to manage and deploy, but it's sitting on top of the Java Virtual Machine so it can be deployed to any servlet container or J2EE application server and can take advantage of all of the tooling available for deploying and maintaining Java applications (JMeter, Maven, etc.).

Is this more clear?

you've got to be kidding; PHP is a better Cold Fusion than Cold Fusion ever was

Haha! Having developed with both languages I can honestly say that Coldfusion (one word) simplifies 90+% of the tasks that you would need to use on a regular basis. Is PHP more feature rich, perhaps, but you're not land locked with CF. It allows you to delegate to any other jvm runnable language(in the same execution context, ie. Pass variables between) if need be.

You (and others) should give it a try, you will be pleasantly surprised by its simplicity.

I need more than a simple fan boy boast. Download it first and then tell me why.

I've done my time in Cold Fusion hell, I know what I need to know.

Perhaps I've got a negative attitude about the intelligence of developers because I've been a maintenance programmer for too long. I've seen so many apps that almost work in ColdFusion because some guy didn't know if he was using a session scope or an application scope or request variable in CF.

I worked at a place where there was a ColdFusionMafia that existed just to bamboozle management into shelling out $8000 for server licenses. They'd go blah blah blah about how Cold Fusion was a great force multiplier but most of them couldn't code their way out of a paper bag they just knew a bunch of tricks that almost worked but couldn't be bothered to get HTML and SQL escaping right.

To be fair you can write pretty decent code in CF if you know how to code but if you knew how to code why would you be coding in CF?

The ColdFusionMafia ultimately got the organization to spend upwards of $500k worth of software licenses and people's time to implement a commercial CMS product that was ultimately abandoned. They pulled me off a project that was really worthwhile and it ended up in a project failure that caused my whole group and everybody above it all the way to the top of the organization to get fired.

Some recruiter called me the other day wanting to know if I want to code ColdFusion in Ohio and I'm like I'd rather be shuffling punched cards....

Sounds like a bad job. I've had bad jobs but I've never blamed the language.

CF is easy to get started in, so is PHP. I've seen some horrible spaghetti code in both languages. That doesn't make either of them bad.

I like CF because I like writing fewer lines of code to get things done. That doesn't stop me from looking at other languages seeing if something is better.

In fact some members of the community are blogging the seven languages in seven days book, not all of us have blinders on;<).


Missed one:

    foobar() is the same as FOOBAR()
    $foobar is completely separate from $FOOBAR

This horse has been beaten, mutilated, and buried.

Obviously not quite buried yet.

#40 is a major WTF. They are outright removing the ability to create a length 1 buffer, so that someone who wants to create a 4096 unit buffer can save 3 keystrokes?

(Also, what if the length argument is dynamically generated, say from the size of a file?)

Programming languages are tools. Some tools are better than others, some are better for certain situations. For all non-contractors, no one is forcing you to write in one language over another (or stay employed at a php shop).

It seems like the only point of having threads like this is for the leet programmers to look down on php. What's the point? This isn't constructive, its condescending and back-patting.

(the reason this makes me mad is that the sadness list is just a bunch of minor gripes. Every language has minor problems. PHP has fundamental flaws and that causes sadness, not this crap.)

What makes me sad is that even though I feel affronted by PHP's crudeness, inelegance and inconsistencies… I keep using it for a lack of another language that suits me personally.

I hate PHP's runtime and core libraries. But I really like the C-inspired syntax. I use Objective-C as my main other language, and something about Ruby and Python's syntaxes seem to rub me the wrong way. I'm giving Node.JS a whirl these days—and while I might be able to get used to closures everywhere, I don't know how to feel about the lack of true object orientation.

This is by far my (least?) favorite:



The following things are considered to be empty:

- "" (an empty string)

- [...]

--> "0" (0 as a string) <--

- [...]

- var $var; (a variable declared, but without a value in a class)


Why the heck is "0" considered empty?

there's something wrong with the == and coercion in the if() statement in any language.

making the switch in if() be a boolean only pushes the problem off to the programmer, who will often choose the wrong function or expression to do the conversion

> making the switch in if() be a boolean only

What exactly is the alternative?

If there's any problem here it's automatic coercion.

Nothing wrong with automatic coercion, as long as the rules are sane.

In ruby, everything except false and nil is true. Easy.

Unless you override the == method of course. With great power...

PHP's rules, like Perl, does what the programmer wants a high fraction of the time. Except when they don't.

For instance, 0 == false isn't too crazy, it's like C. But automatic coercion of string values to ints makes "0" == false which is sometimes what you want and sometimes not.

Practically this burns people in form validation code because often you want to test if a field is an empty string and if you do the obvious thing you can end up kicking out "0".

When I write PHP I have my own "PHP on nails" library that has functions that smooth out most of the things that are wrong with the language, and one of them is a comparison operator that is somewhere between "==" and "===" that most frequently does what you want it to do.

in statically typed languages like Java, C#, Scala and C++ people are always screwing this up

most languages have some screwed-uppedness about collections, both intrinsic to the language and that gets introduced by people who make APIs that aren't well designed. for instance, arrays and Lists are often not quite perfectly uniform (and it's often a thoughtless arbitrary choice if people decide to return you one or the other) Scala introduces it's own collections that provide more confusion when you're working with Java. The .NET framework has a great implementation of generics (makes Java and Scala look like a joke) but there are still many legacy APIs in the .NET framework that use non-generic collections.

One result is that it's not always obvious what the right way to test for "empty" is. One of the worst of them is that pretty frequently APIs will give you a null when they ought to be sending you an empty collection, so you need to check for null.

How does scala make this more confusing?

Either the types that are returned are scala collections, or they're java collections. If you want to treat java collections like scala collections you can always `import JavaConversions._` and huzzah, shallow conversions and collection uniformity.

Finally, if something has the possibility of being null, you can use the option construct, e.g.

    if (Option(someListThatMightBeNull).getOrElse(List()).isEmpty) { ... }
Or more likely:

    Option(someListThatMightBeNull) match {
        case Some(list) => // do something...
        case None => // do something else...
More than likely if you're dealing with scala libs, things that can be "null" are returning options anyway.

Option[X] is a crock. It's forcing you to write same bulky if-statements that you need to write for null checks.

I want something like NOT NULL in SQL. Can't static typing make it completely impossible that I'll get a null in a situation where it should be completely impossible?

For instance if something is typed as a collection, I'd like to never see null, I'd rather always get an empty collection. If I have to test for None, I'm just adding more bulky code where errors can hide, particularly when the type inference system in Scala is always doing strange things behind my back.

In my mind, automatic conversions make the problem worse in Scala, not better. Code "just works" for the programmer in certain situations no matter how inconsistent people are in the types they use.

The trouble I see is that Scala programmers seem to be pretty random if they're going return an Array, a java.util.List or a scala.util.List. This is really a pain in the ass when I'm trying to access some Scala objects from Java and I don't have automatic conversion available. I'm also sure that these different choices have all kinds of effects when you consider inheritance, variance, type inference and all that. It adds to the problem of spooky action at a distance in Scala.

You have never looked more than 5 seconds at Scala, right?

Option[X] is only a crock if you haven't understood it. Stop thinking of it as a "null check", start as thinking of it as a collection which can either hold 0 or 1 elements and then you are on the right track.

null in Scala mostly exists for Java compatibility.

Re: Collections ... you haven't looked even _once_ at it. All collections return an empty collection or None, based on the operation. There are maybe 2 methods in the whole Scala standard library which return null, and both are _not_ in the collection framework.

This is so unbelievable misinformed... I can't believe it you have no problem showing this level of ignorance publicly.

"type inference system in Scala is always doing strange things behind my back" ... Example please.

"Automatic conversions" WTF?

"The trouble I see [...]" this is so much pure bullshit.

I am glad that this sort of error is much harder to make in statically typed languages like Haskell.

You should check out JavaScript - the type coercion is similar but even worse.

but JS isn't behaving weirdly with return values. Overall, JavaScript is much less WTF than php.

It's impressive how they managed to do that, given that PHP is a single open source platform with one major implementation, in contrast to JS.

php -r 'array("a","b")[0];' results in a parse error.

Resolving arrays like that causes parse errors in a range of contexts. Anything that is a "function" cannot also pick one array key... leaving a lot of XML-parsing code that looks like

$xml = getXpathWhatever(); $xml = $xml[0];

Stranger yet, is that it works perfectly fine with resolving objects... for example

$xml = funct()->something->somethingelse()->a

Works fine...

Array brackets after function calls are fixed in PHP 5.4:

~/php_source/php-src-5.3$ ./sapi/cli/php -r "function a() { return array(1,2); } print a()[0];"

Parse error: syntax error, unexpected '[' in Command line code on line 1

~/php_source/php-src-5.4$ ./sapi/cli/php -r "function a() { return array(1,2); } print a()[0];"


I usually write it as

$xml = reset(getXpathWhatever());

which returns the first element from array.

Where are the links to his bug reports for these so we can vote on them to be fixed?

The PHP bug report tool is at http://python.org. To file a bug, click 'Download Python'.

PHP is Open Source. Compiling a list like this is nice, but contributing something back, and getting involved in making improvements to PHP, would be nicer.

The core team has it's own priorities, and has a history of ignoring the requests of the dev community. A couple of examples: in version 5.3, they added `goto`. WTF. Who, after five major releases, decides that what a language really needs is `goto`.

In the same release, they decided to finally add namespaces. But, despite the tired claim that PHP takes cues from C/C++/Java, they did not reuse :: (aka paamayim nekudotayim) as the scope resolution operator. Instead, they devised a new operator: '\'.

There is an IRC log somewhere where you can read the painful arguments back and forth over what this operator should have been. One of the rationalizations for the backslash was that it makes sense to Windows developers, as they are already familiar with the idea of '\' being used to separate elements of a hierarchy.

The end result:


Attribute/Method access: foo.bar

Static method access: Foo.bar

Package access: foo.bar.baz


Attribute/Method access: foo.bar

Static method access: Foo.bar

Namespace access: foo.bar.baz


Attribute/Method access: foo.bar

Static method access: Foo.bar

Module access: foo.bar.baz


Attribute/Method access: $foo->bar

Static method access: Foo::bar

Namespace access: foo\bar\baz

None of these languages except for PHP have their own string concatenation operator. They overload + for that purpose. They're also all strong typed languages while PHP is weakly typed. Overloading + for string concatenation in a weakly typed language is a recipe for disaster (see JavaScript).

> Who, after five major releases, decides that what a language really needs is `goto`.

It makes it a much easier compilation target.

> But, despite the tired claim that PHP takes cues from C/C++/Java, they did not reuse ::

They couldn't because unlike C/C++/Java the entire project isn't compiled at once. At compile time, PHP has no idea that the symbol preceding the operator is a class name or namespace from one run to the next. It might have been possible to resolve that with major changes to the underlying engine or maybe not. I absolutely hated the idea of the backslash when proposed but after using it for a while it seems fairly comfortable.

I know that there are reasons for this behavior. None of them are good, however. Why couldn't they reuse the same resolution operator for all three, even if it's not the period character?

Looking at your responses all over this post, there is a big disconnect. Other people -- who probably use and enjoy other languages -- raise issues with PHP that point at poor design. Then you respond with a rationale for why the well-designed thing couldn't be done. (Or, why the poorly-designed thing was done.)

But all designs have rationales. The point is that the people who make design decisions for PHP choose poorly. Even if you give us the rationale, that doesn't make it a good decision in retrospect.

Also, could you explain this statement please:

> It makes it a much easier compilation target.

Do you mean that other languages can be compiled to PHP more easily? Because I have never heard this rationalization before.

> Why couldn't they reuse the same resolution operator for all three, even if it's not the period character?

It may have been possible to do that when the language was originally designed but PHP has taking the long road to getting real OOP. PHP3 had objects but no inheritance; they were really just structs with functions. PHP4 added a lot more ability but, for reasons of compatibility, left a few things unchanged that should have been changed. PHP5 fixed most of those remaining issues and continues to add more features with every release. PHP wasn't designed all at once and things were added as developers demanded them. It was just supposed to be a procedural languages like ASP/VBScript but as a mix of C and Perl; all this object oriented stuff wasn't in the original plan. It now has namespaces and exceptions and all kinds of things that nobody imagined it would ever have. So they can't use one operator for all because each operation compiles down to something different (each from a different time) and that difference needs to be known at compile time without the benefit of knowing what the symbols resolve to.

> Other people -- who probably use and enjoy other languages -- raise issues with PHP that point at poor design.

This is a poor argument. I use and enjoy many other languages. In fact, I'm hardly doing any PHP development right now but I've got half-completed side project I'd like to finish. There's no argument: PHP has a poor design. But if you put things in the context of history, there is reason for that poor design.

> Then you respond with a rationale for why the well-designed thing couldn't be done.

I'm just stating the facts. In this case, it's not like they're going out of the way to be difficult but they have to work with what they have. If you have a time machine we could solve this once and for all.

> that doesn't make it a good decision in retrospect.

Of course, but hindsight is always 20/20. Perhaps Python should have had unicode to start with and should have never made print a statement instead of a function. Perhaps templates were not the best way to add generics to C++. See, we can play this game all night.

> Do you mean that other languages can be compiled to PHP more easily? Because I have never heard this rationalization before.

Yes. That rationalization was one of the reasons for adding it although more in the context of targeting parser generators (like lexx and yacc) to PHP. Even Dijkstra didn't think that goto should been banished from all languages forever.

> This is a poor argument. I use and enjoy many other languages.

Not suggesting that you don't use good languages (unless you use and enjoy PHP). Just saying where other people are coming from.

> Of course, but hindsight is always 20/20. Perhaps Python should have had unicode to start with and should have never made print a statement instead of a function. Perhaps templates were not the best way to add generics to C++. See, we can play this game all night.

The only response I really have to this is that, when some other language teams realize they need to change, they have a better process for setting the future direction of their language.

Much of the fail you describe as being the result of accumulation is really, in my mind, a failure to set or predict the direction of the language.

> unless you use and enjoy PHP

I use an enjoy PHP. I assume that you don't use PHP because if you did, you wouldn't be arguing over such trivial things. For example, the inconsistency of namespace/class/member access looks terrible in theory but in practice it hardly makes any difference. It's not like you get confused as to which one to use and having them look different is somewhat helpful in understanding what the code actually says.

I used to think the backslash was the worse possible thing that could ever been done to PHP but after using it extensively for a while, eh, it's not so bad. At this point, I'd gladly change a whole bunch of other stuff before I'd change that.

> Just saying where other people are coming from.

Hey, I know where other people are coming from. I think I might be more qualified to bitch about the language than those who don't use it day to day.

I use it every day at work, and have been a PHP programmer for years -- however, I don't suffer from the Stockholm syndrome that requires you perform the mental gymnastics involved in rationalizing away sheer volume of fail.

We both work daily with a horrible language, but at least one of us realizes it.

I don't think we're having the discussion you think we're having; I'm well aware of how "horrible" PHP is. But I program in plenty of languages and there is very little difference in code size, code organization, or pain between my code across those languages. I could translate my current PHP project in Python and the differences wouldn't be that great.

I imagine you haven't experience any real pain: programming large projects in VBScript, C++, or doing any work in COBOL. The minor irritations of PHP is just that.

I suspect your problem isn't so much PHP but the code that you have to work with written in PHP. Most PHP code is embarrassingly bad. I'm lucky that, for the most part, I don't have to deal with a lot of terrible PHP code. I bend PHP to my will, not the other way around. A lot of people fault the language design for the insane way people use it -- it doesn't have to be that way.

We're mostly on the same page.

I indict the language designers for making it easy to write bad code. I agree it doesn't have to be that way, people can write good(-ish) code in PHP. It's just that the language team seems to go out of their way to make a language that doesn't appeal to a programmer's sense of symmetry, elegance, consistency, flow, and ease.

All of these things are easily worked around. As a sum though, they contribute to the overwhelming sense that the tool is created by -- and by extension, for -- dumbasses :)

Thankfully, the amount of PHP I have to maintain is decreasing and the time I spend on my own projects is increasing, which is when I get to use better languages.

In previous lives I have had to maintain/develop C++ as well, and I understand that it's painful. All pain is relative, I suppose. I'm sure a woman who has given birth to quadruplets would scoff at this notion of pain.

There's an outstanding request for better array syntax. It's been out there for over 3 years and received a lot of support from the community. At least one implementation has been submitted. But the core dev team rejected the idea, as they are convinced having second syntax available would harm ease of use (and thus popularity) of the language.

In general, some aspects of PHP will not be fixed/improved for reasons of either:

* backward compatibility, or

* incompatibility with the vision of the language by the core dev team.

http://marc.info/?t=121142259100001&r=1&w=2 http://marc.info/?t=119995974300003&r=1&w=2

This is being revisited as per the PHP 5.4 TODO. My guess is it'll happen this time around, and I voted against it previously (but changed said vote). https://wiki.php.net/todo/php54

Indeed, one of the downsides of Open Source... politics etc, it doesn't help, but tends to come with the territory.

Many flaws in PHP are unfixable without breaking compatibility, and if you break compatibility you lose the only advantage that PHP has these days.

Raising awareness of what needs to be fixed is the first step.

Agreed, but if you're going to put the energy into picking out what doesn't work, you probably have spent time thinking about how it should be done, so following through is worthwhile for all concerned.

> Standard libc process control (fork/exec/etc) > The libc fork() and exec() functions are not present in PHP by default. > http://www.phpsadness.com/sad/17

Why would anyone writing a PHP app need those? The page just calls it a missing feature without explaining why this is a bad thing.

Don Hopkins gave a thorough list of things which are wrong with PHP.


The function chaining issue (#21) has to be the single most idiotic thing I ever encountered in any language (other than maybe t-sql).

I grok none, but of Python they make me glad

By popular demand, I've added a discussion board to phpsadness.com. Join the discussion!

things about php that make me sad:

1. it exists

2. it's used

3. many of its users make more money than me

4. it has poisoned the market, clients have learned to expect and even demand php-braindeath

I often find that PHP coders lack a total understanding of the LAMP stack. "Apache configuration? Huh? I don't know, our admins do that." "MySQL? I don't know, I'm not a DBA. I'm a developer." "UNIX commands?!! I don't like going in the terminal. I'm a developer." No, sorry, you're not a developer. You're a glorified web page editor.

Is PHP that different from other platforms in this regard? Any Java programmer knows ins and out of Tomcat, any ASP programmer is MSSQL expert?

* > Any Java programmer knows ins and out of Tomcat, any ASP programmer is MSSQL expert?*

I'd hope they are experts, or at least have no trouble learning quickly. If they can't manage MSSQL or Tomcat, how do they set up their local development environment, implement automated integration tests, etc?

They inherit it from whoever worked on the code before them.

I work on Java every day. I probably have a better grasp of Tomcat than many people at my company. If we somehow magically lost all our Apache/Tomcat configuration files, there's no way in hell I could build it from scratch.

(I can, however, build a scalable system based around PHP web apps with my eyes closed. I'm not super proud of that.)

Bullshit. You don't have to be a sysadmin to be a developer. Web devs often know the whole stack, but you're still a web dev if someone else in your company handles those parts..

You missed the point: they are talking about people who do not know those aspects of the LAMP stack, not the ones who can afford delegating them to DBAs and sysadmins. The first group are indeed glorified web page editors.

Again, bullshit. I've had PHP projects that were entirely command-line with no Apache and MySQL. If you want to argue that those projects weren't development, that's absurd.

Systems and database administration are hugely complimentary skills, but someone who doesn't know anything about setting either one up is still developing.

I agree with you in a literal sense. I'd add the adjective 'extremely poorly' to 'developing' for any developer who doesn't have a thorough grasp of the system for which they are developing.

An artist can make great art without knowing the details of how the dyes in their paint are manufactured. The same is true for development.

Can an artist make great art without knowing to use oil paint on canvas, instead of watercolor (or whatever - I'm not an artist)?

How about knowing the difference between types of brushes and what effect they have on the canvas? Is it 'great art' if it's accidental?

Yes, and yes.

That said, this is more like arguing that you can't be a great artist if you don't know how to make the canvas yourself.

Exactly. I'm trying to get into the state where the only machine where I have root is my phone or laptop.

I can't even imagine how many developers out there started with WordPress and think the ramshackle way it's put together is normal.

Probably the same type of developer that assumes WordPress is an example of professional PHP code.

It's true. The problem is it's often the only PHP code they know. Many people do assume it's an example of good code, since it's so popular and essentially works.

WordPress is really an excellent companion to PHP itself - created by beginners who had no idea about how to design a language or framework. They have each since become somewhat respectable, but are shackled by the attempts they made to preserve backwards compatibility in the early days.

What makes me sad is that people will defend this horrible language to the death, regardless of how many problems there are with it. I don't get it; we know how bad PHP is, so why do people fight so hard?

Oh, and to demonstrate: "PHP has no native Unicode type, no native Unicode handling, and cannot treat Unicode strings as strings." This true statement, composed of three observations about deficiencies in the language, gets me flamed every time I mention it. Why?

> "PHP has no native Unicode type, no native Unicode handling, and cannot treat Unicode strings as strings." ... gets me flamed every time I mention it. Why?

perhaps because statement of of fact (``PHP has pluggable Unicode support'') beats wrong statement of oppinion (``PHP is bad because has no support for it''). It's borderline trolling to insist PHP does not, when people have been using it successfully in production for years now.

http://pl2.php.net/manual/en/book.mbstring.php in case your google is broken.

I knew you were going to point out mbstring. I am talking about an actual Unicode string type. I am talking about using regular string functions on Unicode strings without caring whether or not they contain characters not in ASCII or Latin-1. I expect you'll next talk about how the function overloading "feature" is the correct thing to do, and you'll conveniently ignore how the documentation recommends against it and warns of undefined behavior.

Here's a fun question: How do you strtok(), implode(), or explode() mbstrings?

For background:

- I've seen the Python (2.x) way (separate `unicode' and `str' type and no way to set own conversion defaults per whole process -_-') and found it unwieldy. Lotsa boilerplate to keep around I/O.

- I've seen the GNU way (messy pile depending on LC_* environment vars and files in /usr/, with hierarchy of precedence) and disliked it.

- I've seen the Plan 9 way (char * / char[] for UTF-8 and Rune * / Rune[] for UTF-32) and it fits me. I see and use (non-PHP) software built on that, works reliably. I'm happy :)

implode() and explode() work with UTF-8. I hope you know the techicalities of why -- UTF-8's been designed that way and the functions take complete string as the glue/separator. No idea about about UTF-7, -16 or -32 (nor the April Fool's -18 and -36); guess some of those would break terribly. I don't care at this moment. My sites run polish, english, russian and in near future czech language based on UTF-8.

Your point is just strtok(). You are right. I lost. PHP lost. Have a nice day -- and kudos for bringing up that cool function :-)

EDIT: now that I think about it, it seems I've abused explode() for that job -- the output array, with empty strings removed, is equivalent of calling strtok() repeatedly till it returns FALSE. Seems a bit brute-force-ish.

AS for that warning against, and undefined behavior, I'll assume you're refering to the following passage:

  It is not recommended to use the function overloading option in the per-directory context, because it's not confirmed yet to be stable enough in a production environment and may lead to undefined behaviour.
Reading comprehension: don't re-configure it per directory (in this case, of your project, not whole server). Having that minded, you get reliable site.

Are you serious? You can't figure out why this is?

Seems logical to me. These defenders are presumably professional PHP developers. They're presumably supporting their families by coding PHP. The more widely-spread the language is, the more it's used for new projects, the more lucrative and interesting their work will be.

And here you are, making a fuss, and many of these people may know ONLY PHP. And you're trying to argue that their most valuable skill should be put on the trash heap.

That's why THEY fight so hard: They're feeding themselves with the language.

Now, why do YOU fight so hard against them?

I fight against technologies I perceive as bad choices in an attempt to convince younger developers with less of an experience base that they should pick up something else that will give them the same or better capabilities for much less pain. My contribution to the community, as it were, as I have in turn benefited in my career from such signposting.

You can carve out a decent subset of PHP, but there's this painful and dangerous beginning and middle part where you're still learning this subset and in the meantime you're writing grossly insecure code. Perl has much the same problem. There are no languages I know where you are immediately writing brilliant code, but there's certainly ones you can learn faster, cut down the danger period, and also have many of the worst dangers ameliorated by much better design decisions at the API and language level. (How much of PHP and all similar languages would have been better if only the default interpolation HTML escaped everything and you had to especially ask for direct interpolation, instead of the other way around?)

And you know, none of that offends me. But to act incredulous that professionals who have spent thousands of hours mastering a skillset might actually defend it publicly seems naive.

The implication is that anyone who has spent thousands of hours mastering PHP should be well aware of its bad points, and can only contend that its "good enough for the job".

It's bad, but it's also very, very good.

What aspect of PHP is "very very good"? Genuinely curious to know.

It's bad for language purists, but it's very, very good for getting stuff done fast, easy and good-enough.

See Facebook etc.

A lot of programmers don't believe that a shoddy language (in terms of language design) can be effective, but it is.

I also happen to think that PHP scales really, really well the range that most sites need (say, from 1 to 50 servers). In that range, PHP is almost never the bottleneck.

> "very good for getting stuff done fast, easy and good-enough"

You're saying PHP facilitates a faster development process than most other popular web development platforms? This was probably true, ten years ago.

Today, we have several platforms that facilitates a fast development process without the language weaknesses and inconsistencies that PHP is burdened with.

Mandatory function arguments:

    function foo($arg1,$arg2) { return; }

    Warning: Missing argument 2 for foo()
Lame. But omitting arg2 is allowed if you give it a default value:

    function foo($arg1,$arg2=FALSE) { return; }
Blah. Instead I'd rather make arg2 truly optional just by testing if it's defined.

I see this as a feature. (I'd never thought I come around to defend PHP. Issue #21 has bitten me in practice.)

I really don't mind this, I have more more control because of it. If I want the function to error out upon arg omissions, I will demand arguments.

If I don't require args: function foo($arg1=null, $arg2=null) {return;} foo(); // return no error

This is great for me, when I am writing an API and have some args that are required and others that are optional.

What would the ideal language return for your function call foo('bar'). It would seem to me that missing an argument should return some sort of notice, like in the case where someone else is using it.

I prefer Javascript for example: JQuery's calling conventions would not be possible if function args were mandatory.

I'm curious as what PHP couldn't do? You have default argument values and you can pass more arguments to any function. Seems that covers all the cases.

You can always use func_get_args() if you truly want it that way.

Or you could just use a real programming language that has some kind of design.

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