top | item 2591845

These are things in PHP which make me sad

243 points| johnkary | 15 years ago |phpsadness.com | reply

212 comments

order
[+] larrik|15 years ago|reply
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.)
[+] dexen|15 years ago|reply
compact() + extract() is the closest you get.

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

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


  function myFunction($kwargs) {
    $foo = SOME_DEFAULT_VALUE;
    extract($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().

[+] steve-howard|15 years ago|reply
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

    do_something(@$_GET['foobar']);
There are ways to suppress PHP notices without just turning off the E_NOTICE output.
[+] blake8086|15 years ago|reply
Isn't a wrapper function the solution to this? Or even... a wrapper function that takes an associative array of options as an argument.
[+] pornel|15 years ago|reply
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!

[+] jrockway|15 years ago|reply
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.

[+] mrspandex|15 years ago|reply
"#41 Cannot create a final abstract class" is borderline too
[+] programminggeek|15 years ago|reply
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.

[+] iphoneedbot|15 years ago|reply
yeah.. php really has gotten a bad rap.. nearing ASP proportions
[+] thinkcomp|15 years ago|reply
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.
[+] alanh|15 years ago|reply
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.

[+] koenigdavidmj|15 years ago|reply
Even in Hebrew, that is a useless error message...token names should mean what the token means, not what it looks like.
[+] lox|15 years ago|reply
I'm actually quite fond of that particular quirk. At least it's easy to search for!
[+] user24|15 years ago|reply
> 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".

[+] qeorge|15 years ago|reply
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?

[+] gergles|15 years ago|reply
The ridiculously terrible behavior of == is what makes me the saddest.

http://www.php.net/manual/en/types.comparisons.php

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

[+] danudey|15 years ago|reply
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.

[+] qntm|15 years ago|reply
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!

[+] gergles|15 years ago|reply
Wow, a downvote within 30 seconds of posting?

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

[+] wvenable|15 years ago|reply
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.

[+] jwatzman|15 years ago|reply
My favorite PHP design misfeature: what does the following code do?

  <?php
  $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
[+] unfletch|15 years ago|reply
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.

[+] pornel|15 years ago|reply

    unset($bar)
after the first loop is highly recommended.
[+] jrockway|15 years ago|reply
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.

[+] ckoning|15 years ago|reply
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).
[+] cgranade|15 years ago|reply
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.
[+] nimrody|15 years ago|reply
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).

[+] eru|15 years ago|reply
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.
[+] ars|15 years ago|reply
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?

[+] stevep98|15 years ago|reply
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 )

Note:

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.

http://us.php.net/manual/en/function.implode.php

[+] betageek|15 years ago|reply
PHP's single greatest advantage is ubiquity - would love to see a CoffeeScript compiler for PHP that smooths out these issues.
[+] PaulHoule|15 years ago|reply
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.

[+] DCoder|15 years ago|reply
Missed one:

    foobar() is the same as FOOBAR()
    $foobar is completely separate from $FOOBAR
[+] sparkygoblue|15 years ago|reply
This horse has been beaten, mutilated, and buried.
[+] jessedhillon|15 years ago|reply
#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?)

[+] Androsynth|15 years ago|reply
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.)

[+] SeoxyS|15 years ago|reply
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.

[+] gburt|15 years ago|reply
This is by far my (least?) favorite:

http://ca.php.net/empty

-----

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?

[+] PaulHoule|15 years ago|reply
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

[+] code_duck|15 years ago|reply
You should check out JavaScript - the type coercion is similar but even worse.
[+] jcampbell1|15 years ago|reply
php -r 'array("a","b")[0];' results in a parse error.
[+] gburt|15 years ago|reply
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...