Exhibit 1a

("false" == 0) returns true

No fucking joke. What a pile of turd.

It gets worse though.

  1. ("false" == 0) returns true.
  2. (false == 0) returns true.
  3. ("false" == false) returns false.

Identity in PHP is non-transitive. A == B, B == C, but A != C. Utter logic fail.

It's just not the case that false and "false" are the same. One is a bool and the other is a string. Technically, '==' in PHP means "equals to" - to check identity, you need to use the triple equals "identical to". This is so silly. Python and Ruby don't require this kind of thing. Another way around this is to explicitly cast all the operands in a PHP 'equal to'.

This can lead to confusion for newbies. ("foobar" == 0) and ("1" == 0) return different values. One has to explicitly remember that "0", "1", "true" and "false" have special values.

There's no reason why '==' should mean anything other than identity. In Ruby, there's a nice principle applied - the principle of least surprise. That '==' has a strange and fuzzy concept type-specific equality rather than a strict identity comparison is surprising. Read PHP types comparsion and tell me that loose comparison isn't totally surprising and baffling.

Why is this important? Some people see this and tell me "oh, well, it's just one of PHP's many lovable quirks. Just use triple-equals". That'd be fine if PHP weren't the language picked so often by beginners. PHP has taught a wide swathe of people that "==" means something other than it means in all the other languages they might use in the future.

"It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration." (Dijkstra)

s/BASIC/PHP/g; Christ on a fucking wheel, I hate PHP likeness operator.

Exhibit 1b: Likeness Harder, With a Typecast Vengeance

If you think the likeness operator sucks - if you don't, go compete in the Darwin Awards - you just gotta see the version with explicit type casting:

((string) "false" == (int) 0)

What does that return? TRUE. I'm not fucking kidding. You'd think explicitly casting the literals might tip off the interpreter that I care about the types. Yes, yes, it's doing what it should be doing according to the likeness documentation. It's rigidly following a moronic rule.

Exhibit 2

Goto. Apparently, it's for low-level programming. Programming that is low-level enough to require a goto (hint: you don't need it for your blog. I promise.) but not quite low level enough to write it as a C extension. That makes sense.

Do note that the PHP guys added a new language literal for this - "procedurename: { /* code */ }". Remember that when closures or $yourFavouriteLanguageFeature gets rejected because it would clutter up the syntax.

Exhibit 3

The functions of the standard library are a mess. They manage to include both camelCase, underscore_separation and C-style function names like strpos. Instead of proper namespacing and OO, they simply use prefixing as a pseudo-namespace, which is pretty horrible because it means every time you type a function name you have to type prefix_function_name(whatever).

PHP 5 should really have deprecated the array handling which is a crazy mess of badly named functions.

Here is the list of functions for handling arrays in PHP:

  1. array_change_key_case
  2. array_chunk
  3. array_combine
  4. array_count_values
  5. array_diff_assoc
  6. array_diff_key
  7. array_diff_uassoc
  8. array_diff_ukey
  9. array_diff
  10. array_fill_ keys
  11. array_fill
  12. array_filter
  13. array_flip
  14. array_intersect_assoc
  15. array_intersect_key
  16. array_intersect_uassoc
  17. array_intersect_ukey
  18. array_intersect
  19. array_key_exists
  20. array_keys
  21. array_map
  22. array_merge_recursive
  23. array_merge
  24. array_multisort
  25. array_pad
  26. array_pop
  27. array_product
  28. array_push
  29. array_rand
  30. array_reduce
  31. array_replace_recursive
  32. array_replace
  33. array_reverse
  34. array_search
  35. array_shift
  36. array_slice
  37. array_splice
  38. array_sum
  39. array_udiff_assoc
  40. array_udiff_uassoc
  41. array_udiff
  42. array_uintersect_assoc
  43. array_uintersect_uassoc
  44. array_uintersect
  45. array_unique
  46. array_unshift
  47. array_values
  48. array_walk_recursive
  49. array_walk
  50. array
  51. arsort
  52. asort
  53. compact
  54. count
  55. current
  56. each
  57. end
  58. extract
  59. in_array
  60. key
  61. krsort
  62. ksort
  63. list
  64. natcasesort
  65. natsort
  66. next
  67. pos
  68. prev
  69. range
  70. reset
  71. rsort
  72. shuffle
  73. sizeof
  74. sort
  75. uasort
  76. uksort
  77. usort

Compare PHP:

$array = array(1, 2, 3, 4, 5);$array = array_reverse($array);echo implode(" ", $array);

Ruby:

array = [1, 2, 3, 4, 5]array.reverse!puts array.join(' ')

That seems okay, but if you boil that down to one-liners, the crapness of PHP shines through:

echo implode(" ", array_reverse(array(1, 2, 3, 4, 5)));vs.puts [1, 2, 3, 4, 5].reverse.join(' ')

For the human reading this, the latter (Ruby) code, except for the puts at the beginning (I'm tempted to monkeypatch .puts in as a method on Object that would just run puts on .to_s), is readable left-to-right. First, you get the array, then you get the reversal, then you get the join. With PHP, it's the other way around. You get the implode function (which is a stupid name btw: you aren't making the array implode, you are joining the members of the array into one object, a string), then you get the reversal of the array, the finally you get the array. If you are coding in Ruby and you decide you don't want to reverse the array, you simply delete ".reverse" from the code, while in PHP, you have to remove the "array_reverse" and the two brackets. If you've got 500 lines of this crap, you can easily write a regex that removes every ".reverse" method in the code, but doing similarly for removing nested function calls is a pain in the arse.

Here is a radical idea: in PHP6, get rid of all this shit. Replace it with proper classes and objects. Maybe not everything - at the most, leave numbers and basic maths operators (use class methods for the rest, as per Java). Whatever. There is no reason arrays, strings or whatever needn't be objects. Just do it and tell everyone to get fucked if they don't like it.

Exhibit 4

PHP's array is both a list and a hash at the same time. Let's say you are writing some library code. If you were doing it in Java, you'd be explicit about your methods and say whether or not they were expecting, say, a String[] or a HashMap or a List or whatever. In PHP, you put in your docs that the method or function takes an array. But if an array can be both a list and a hash, what should you process?

Let's say you are expecting a list and you pass it a hash - sorry, an associative array - then you might just iterate on value. But flip it around: if you are expecting both a key and a value, and someone passes you an array containing only values, then what?

The whole thing is such a mess. It's much simpler just to say a list is a list and a hash is a hash and if you need anything more complicated than that, define your own class or struct for it to go into. Christ, perhaps I should write a proposal to the JCP to replace all the java.util.List subclasses with just java.util.Blob (and then we'd need AbstractArbitraryBlobFactory and a few interfaces). It'll make everyone's life so much easier.

Powered by WiGit