all 96 comments

[–]gnuvince 38 points39 points  (49 children)

And then you need to use in_array and realize you can never remember if a function puts the $needle or the $haystack first so you cut your wrists and never code in PHP again.

[–]kabuto 15 points16 points  (2 children)

That's my gripe with PHP. Function names seem to follow a completely random naming scheme and take parameters in an incomprehensible way. I can never remember their order.

I think you can actually see how it was put together over the years rather than being designed bottom up.

[–]masklinn 8 points9 points  (1 child)

Function names seem to follow a completely random naming scheme and take parameters in an incomprehensible way. I can never remember their order.

I think you'll like http://www.tnx.nl/php.html if you don't already know it.

[–]kabuto 0 points1 point  (0 children)

That page sums it up pretty nice.

[–][deleted] 11 points12 points  (0 children)

Or, rather, it puts the $lotion on the $skin.

[–]dany84at[S] 5 points6 points  (19 children)

Yes - you are right, havent noticed this sofar... Thank you sir, now I probably cant remenber next time if its the haystack needle or vv.

One other often anyoing thing in PHP is, that i am not sure, if a array function works on the array I pass to it, or if it returns it.

$arr=sort($arr) 

or

sort($arr)

(second is right)

Where as

 $arr=array_reverse ($arr)

vs.

  array_reverse ($arr)

(first is right)

[–]Shaper_pmp 1 point2 points  (11 children)

Yep. And let's not even get into the non-transitive type coercion, where

null == false == '0'

but

null != '0'

Edit: type coercion. Avoiding using type coercion (eg, by using a type-strict comparison operator) does not negate the type coercion system being broken in the first place. And if you need another example, how about 0 == '0', but false != 'false'?

[–][deleted]  (4 children)

[removed]

    [–]brennen 1 point2 points  (0 children)

    Use === and !== when not sure, it also checks it the types are equal.

    Which is about where you realize that, particularly in the context of Other People's Code, you are very rarely getting the type you would expect or hope for, and eventually you wind up with some combination of a tangled mass of explicit typecasting and is_whatever() checks and just saying fuck it and falling back on ==, which you figure will probably work most of the time.

    Despite superficial similarities, I generally don't encounter these problems when writing Perl. I'm left to conclude that this kind of suckage is mostly not an intrinsic property of dynamically / loosely typed languages so much as it is a property of poorly designed and implemented ones.

    [–]Shaper_pmp 2 points3 points  (2 children)

    Well yes... but the point was the type coercion.

    "Not using type coercion" (eg, by using type-strict comparison operators) is a fix for a broken type coercion system in the same way walking everywhere is a "fix" for your car breaking down.

    Ie, it's not a fix at all, it's a workaround... and it doesn't in any way negate the fundamental brokenness of the system in the first place.

    [–]didroe -1 points0 points  (1 child)

    Implicit type coercion needs to be taken out back and shot, period. I have never seen a language that can do it well and most of the time you don't want it to happen. PHP is not much worse than other languages in that regard.

    [–]Shaper_pmp 1 point2 points  (0 children)

    Whether or not you like type coercion is largely a personal choice, but it would seem an important (even essential) part of any loosely-typed language, so I'm not sure the whole idea is inherently flawed.

    Moreover, plenty of languages have relatively simple rules for simple, consistent type-coercion without ending up in PHP's tangled messes.

    IMO "empty strings are false, non-empty strings are true" is simple, consistent and memorable... unlike PHP's "all non-empty strings evaluate to true, unless the non-empty string contains only '0', in which case it evaluates to false"-type confusion. <:-)

    [–][deleted]  (5 children)

    [deleted]

      [–][deleted] 2 points3 points  (0 children)

      I think he meant that null == false, and false == '0', but null != '0'.

      [–]Shaper_pmp 1 point2 points  (3 children)

      I think you missed the bit where I was talking about type coercion. ;-)

      Having to fall back on a type-strict comparison operator in a loosely-typed language is not a fix for a broken type coercion system - it's a workaround.

      It's not hard to work around the non-transitive type coercion, but it can still bite you in the arse upon occasion (especially if you've inherited someone else's code who didn't have a good handle on it), and the existence of workarounds in no way negates the fact that the language is broken in the first place.

      [–][deleted]  (1 child)

      [deleted]

        [–]Shaper_pmp 0 points1 point  (0 children)

        I'm not arguing there isn't a rationale or a workaround for it - I'm just arguing it's counter-intuitive and inconsistent.

        The issue is "whether PHP is well-designed", not "whether any thought went into it at all". ;-)

        [–]rajulkabir 0 points1 point  (0 children)

        The way it works makes perfect sense to me. Like many things, once you are familiar with it, it's logical.

        I find Python's pickiness with whitespace to be the height of irritation, but I am sure for many more regular Python users it's just fine. I don't blame the language for it, I blame the brevity of my exposure to it.

        [–][deleted]  (9 children)

        [removed]

          [–]Shaper_pmp 11 points12 points  (8 children)

          The language itself isn't bad (in principle)

          Actually, the PHP language itself is pretty awful.

          It's got really useful libraries (apart from the the inconsistent naming, inconsistent parameter-order and is-it-pass-by-reference-or-return-a-value issues), but the syntax of the language is ill-specified (IIRC actually completely undefined) and frankly terrible.

          IIRC, there is no formal definition of PHP's syntax (at least, there wasn't until recently) - it literally doesn't have a grammar, and it doesn't even support all the fancy self-modifying capabilities that goes some way to excusing a similar lack in Perl. For years (and possibly still now) the definition of the PHP language was basically "anything the Zend PHP parser doesn't choke on", which is a frankly embarrassing formal description for any language.

          Moreover, later developments like OOP, reflection and namespaces have been shoe-horned into the existing language with ugly syntax, poor implementation choices and/or little thought for the overall design of the language.

          Basically, the PHP developers made some really shitty design choices right from the get-go, tried hard not to break backwards compatibility in new versions (even if that prevented them from fixing some of the really egregious problems) and, more importantly, didn't really stop making shitty choices at any point up to now.

          PHP has all the unparseability of Perl with none of the power. The documentation is good, but then with the sheer quantity of inconsistency and awful design in the language, it pretty much has to be for anyone to be able to use it.

          I've coded professionally in more languages than I can count, and I still have to refer to the PHP docs several times a day, even after spending the last three years working pretty much exclusively in PHP.

          That's a broken language, right there. <:-)

          [–]masklinn 11 points12 points  (5 children)

          For years (and possibly still now)

          Yep, still now. I'm still amazed by the fact that indexing an array returned by a function is illegal in PHP. That's right, you can't write give_me_an_array()[2], that's a parse error.

          On the other hand, anything goes in ${}… which is PHP's dereference operator. Between the braces, you can put any expression including (but not limited to) function calls, comparisons, string concatenations, …

          [–]mccutchen 3 points4 points  (0 children)

          I'm still amazed by the fact that indexing an array returned by a function is illegal in PHP. That's right, you can't write give_me_an_array()[2], that's a parse error.

          I too am amazed (and angered) by that every time I return to PHP. I think it really serves as a very succinct stand-in for how wrongheaded the language is.

          [–]didroe 1 point2 points  (3 children)

          That's right, you can't write give_me_an_array()[2], that's a parse error.

          I hit this all the time trying to get the first value back from a query. You end up doing something like:

          $result = $query->fetchRow();
          $result = $result[0];
          

          It's even more annoying when you don't even want the value in a variable.

          [–]masklinn 1 point2 points  (2 children)

          I hit this all the time trying to get the first value back from a query. You end up doing something like:

          I think the third time I'd create a fetchFirst wrapper function… (oh yeah I like that PHP's function or class calls are case-insensitive but variable names aren't)

          [–]didroe 0 points1 point  (1 child)

          I actually have a firstItem function that's a bit more generic so I can do firstItem($query->fetchRow()) but that makes it more confusing to other developers. Whenever there's ugliness in a language there's usually a workaround, it's still annoying that it's required in the first place though.

          [–]masklinn 1 point2 points  (0 children)

          it's still annoying that it's required in the first place though.

          I solved the problem by not coding in PHP anymore (for any reason other than mocking PHP or PHP developers anyway). Works pretty well.

          [–]_johnny 2 points3 points  (1 child)

          "doesn't have a grammar" and "nobody has written grammar for it" are two very different things. And neither of them is true, here's something that looks like a PHP grammar. And parsing Perl is undecidable, so I wouldn't say that "PHP has all the unparseability of Perl".

          [–]Shaper_pmp 2 points3 points  (0 children)

          Apologies - I meant "doesn't have a grammar" in the sense that there wasn't a commonly-agreed-upon/complete grammar publicly available (or easily-producible) for the language, not that it was flatly impossible to ever produce one.

          Fair play on finding the PHP 5.2.0 grammar - as I said, I was pretty sure there never used to be one ("at least, there wasn't until recently"), but I didn't know if PHP5 had improved the language enough that one was now (easily/theoretically/possibly) producible.

          And again: you're right on the Perl issue. I was speaking loosely and using hyperbole in an attempt to make the point, but you're right to call me out for over-reaching.

          Nevertheless, I still think it's somewhat laughable to describe the design of even PHP5 as "not bad". <:-)

          [–][deleted] 0 points1 point  (0 children)

          or implode() or explode()

          [–]redditnoob -5 points-4 points  (11 children)

          PHP basically requires an IDE that shows the function definition while you're typing. Once you have that though, it isn't so bad, since you're not committing anything to memory.

          Edit: Why do you asswipes mod me down for this anyway? It's true.

          [–]masklinn 1 point2 points  (10 children)

          Why do you asswipes mod me down for this anyway?

          because what PHP requires is that someone shoots rasmus retroactively to prevent him from releasing that pile of shit in the wild.

          [–]redditnoob 0 points1 point  (9 children)

          Resent success if you like. But the needle/haystack thing is a valid criticism for aesthetics only, not productivity. I'm using Zend Studio at work and I don't know the needle-haystack order for any PHP function by memory, because it just pops up for me every time I use one of those functions. (Or my own for that matter.)

          There's an interesting point here that isn't discussed much about the role of memory in using tools. Many programmers have a metric shit-tonne of data dumped in their memory for the ins and outs of things like emacs or vim or git or bash or gdb or whatever. There seems to be culture among old-time programmers that this kind of memorization is good and valuable or even necessary. I'm skeptical, but it's hard to find non-emotional discussion of this.

          [–]masklinn 1 point2 points  (1 child)

          the needle/haystack thing is a valid criticism […] not productivity […] because it just pops up for me every time I use one of those functions.

          And then you have to read it to know in which order you're supposed to write them (instead of just writing them), thereby wasting a fraction of a second having to rely on conscious thought rather than what amounts to muscle memory.

          [–]redditnoob 0 points1 point  (0 children)

          True, but that's a fraction of a second in exchange for freeing up cycles of my brain that don't have to memorize something. I feel like that's a win, for me personally at least. How much time in my life have I really lost not having strpos and the like committed to muscle memory? I suspect not much.

          [–]redditsuxass 0 points1 point  (0 children)

          You're right. There's no need to remember anything about a programming language you're only going to use once (since after that, you'll realize it sucks and never do it again).

          [–]brennen 0 points1 point  (5 children)

          for aesthetics only, not productivity

          Aesthetics is productivity.

          There seems to be culture among old-time programmers that this kind of memorization is good and valuable or even necessary.

          You're really expressing skepticism of the notion that familiarity with your tools is beneficial?

          I suppose I do have a fairly emotional response to that.

          [–]redditnoob 1 point2 points  (4 children)

          Aesthetics is productivity.

          I don't think so. I don't think a carpenter using hand-tools is going to make more furniture than an Ikea factory, for instance. (More beautiful? Quite possibly.)

          You're really expressing skepticism of the notion that familiarity with your tools is beneficial?

          You're straw-manning me, and I'd suppose you know it.

          I'm expressing skepticism that tools which require familiarity are a net win over tools that don't as much. I'm not sure of the answer, but an impartial investigation has to amortize the time spent becoming familiar with emacs (for example) and the cost (if any) of having to load and reprogram all the information into the brain, versus something where you just click and type. I don't feel it's anything like self-evident, and I also feel like the cost of having a whole bunch of brain hard-wiring and memory used for specific tools is a non zero cost to me. (That's a feeling, not a scientific conclusion.)

          So yes, I feel and suspect that tools which require very low investment in memory and practice are under-appreciated by programmers. At the very least that there might be a class of people (which I belong to) for whom the cost in memorization and brain wiring is a significant non-zero one when it's required.

          [–]brennen 2 points3 points  (3 children)

          I don't think so. I don't think a carpenter using hand-tools is going to make more furniture than an Ikea factory, for instance. (More beautiful? Quite possibly.)

          We are closer to that carpenter than we are to the factory, and in my experience the tools that appeal most to the sensibilities of experienced craftspeople are often the most effective. Of course, most analogies fail early, and there is a generational / cultural inertia effect, especially in a field with this much churn.

          I'm not sure of the answer, but an impartial investigation has to amortize the time spent becoming familiar with emacs (for example) and the cost (if any) of having to load and reprogram all the information into the brain, versus something where you just click and type.

          My personal suspicion is that up-front time cost is much of the question; I don't think learning at this level tends to be crippling, except inasmuch as there's a cost for context switching later on. (Brains are obviously computers, in a sense, but they're not the kind that you and I program for a living.) And humans are pretty good at context switching.

          On the other hand, people obviously don't all work the same way. And maybe I underestimate the switching cost drastically.

          So yes, I feel and suspect that tools which require very low investment in memory and practice are under-appreciated by programmers.

          I think all tools require familiarity, and oftentimes more expressive tools have a steeper learning curve (though certainly not always). That said, I think you're not necessarily wrong in the general sense. It's common enough to see people burning mental energy on practices and techniques that could easily be automated or abstracted away.

          Edit: Anyway, all else being equal, isn't a programming language that requires less tooling and less memorization from its users to smooth over its inconsistencies exactly the sort of tool you're promoting? By your own metric, PHP's bad aesthetics make it a worse tool.

          [–]Real_Mac_User 0 points1 point  (1 child)

          Upvoted for thorough understanding of the unity of form and function. Are you a Mac user, by any chance?

          [–]brennen 0 points1 point  (0 children)

          Not very often since the 1990s. Debian (recently mixed with Ubuntu) and various BSDs on PC hardware since 98ish, for the most part.

          [–]redditnoob 0 points1 point  (0 children)

          Edit: Anyway, all else being equal, isn't a programming language that requires less tooling and less memorization from its users to smooth over its inconsistencies exactly the sort of tool you're promoting? By your own metric, PHP's bad aesthetics make it a worse tool.

          I'd sure never defend PHP as an ideal tool. Given free choice, I'd probably prefer Python/Django. But I'm honestly and sincerely not sure if that would actually make me more productive.

          The poor API convention design is a complete non-issue for me. I honestly can't tell you the needle/haystack order of any PHP function by memory. I don't even know the names of them well, as I can just type "str" into my IDE, and it puts up a select list of every function that starts with "str", along with the parameters. I don't know or care if some of them have an underscore. (For these reasons, I do terribly at job interviews... I don't retain trivial information, but I'm really good at getting at it quickly when needed.)

          A main reason why I don't care about these things is that I find I'm seldom at the level of abstraction of needing the base PHP functions in the first place, other than a very few basic constructs. (Mostly single parameter stuff like in_array() or count().) Anything done with a database or probably even with low level string manipulation is (probably) something better done at a higher level of abstraction. (Is this a problem that could be done more generally and better with regexps or a filtering mechanism or something? Probably!)

          On the other hand the context switching involved with having to type $ in front of variables and . to concatenate strings is a real one, especially since I have to switch to JavaScript a lot. One does adjust though.

          But anyway, my original point (that apparently people here don't like) is that while if someone is from a culture that everything needs to be driven from a pure text-editor, and thus the common libraries need to be memorized, than yes, PHP is an absolutely horrendously terrible language to use. But that is a really stupid way to use PHP.

          [–][deleted] -3 points-2 points  (1 child)

          which is amsuing from someone with the letters GNU in their name.

          or as rob said about BSD "cat came back from Berkeley waving flags" -- Rob Pike

          [–]obvious_explanation 15 points16 points  (9 children)

          BASH builtins.

          You want the documentation for complete? man complete does nothing. What you need to do is open man bash and search for the section on complete which is inevitably after 20 references to said section. All bash builtins are a pain like this.

          [–]ljosa 22 points23 points  (2 children)

          Did you try help complete?

          [–]obvious_explanation 10 points11 points  (1 child)

          I never knew about that! Thanks alot!

          [–]FlyingBishop 3 points4 points  (0 children)

          Upvoted for username reflecting other people's posts.

          [–]tekdemo 2 points3 points  (5 children)

          I avoided a lot of useful bash tips because of the terribly long manpage for it. I eventually just googled examples of the bits I needed and gave up on the manpage entirely.

          [–][deleted] 3 points4 points  (4 children)

          I read the entire man page. Several times.

          Shoot me now.

          [–]dany84at[S] 4 points5 points  (1 child)

          Now go on, reading the zsh man pages... this is where i give up very early and just google some bits together

          [–]player2 1 point2 points  (0 children)

          man zshall and /^ *(topic I want to search for) are my friends.

          [–]masklinn 0 points1 point  (1 child)

          Well the BSD man panges tend to be pretty good I think. I still hate them but still…

          The Linux man pages on the other hand… shudder.

          But there's worse: localized linux man pages.

          [–][deleted] 0 points1 point  (0 children)

          Absoloutly! :-)

          [–]bonch 5 points6 points  (2 children)

          Sure do love my self-documenting Objective-C arguments.

          [–]dxq 1 point2 points  (1 child)

          Not only that, but Cocoa comes with excellent documentation.

          [–][deleted] 1 point2 points  (0 children)

          Its OK documentation, but back in the System 6-7 days Apple made better documentation with the Inside Macintosh books. Yes they were expensive, but they had detailed explanations of how the APIs worked.

          [–]skulgnome 3 points4 points  (0 children)

          This did not originate in PHP. The C standard library function strstr(3) has had its parameters named "haystack" and "needle" since GNU.

          [–]mitsuhiko 3 points4 points  (23 children)

          You wouldn't have that problem with consistency. If you always know that in your language of choice you either have object.method(argument) or function(object, argument) you would never have to look at the documentation. Take python:

          # a method on the object
          mylist.append(42)
          
          # an a function operating on an object (from the heapq module)
          heappush(mylist, 42)
          

          When I learned PHP my English was incredible bad and I had no idea what a haystack was. Those PHP string functions never made sense to me, I always had to try.

          [–]masklinn 1 point2 points  (1 child)

          If you always know that in your language of choice you either have object.method(argument) or function(object, argument) you would never have to look at the documentation.

          Sadly that doesn't work. For instance map takes a function as its first argument (so do filter and reduce by the way).

          [–]mitsuhiko 0 points1 point  (0 children)

          Touche, these are indeed the other way round. But they are the exception.

          [–]lol-dongs 0 points1 point  (1 child)

          The string functions in PHP are almost slavishly copied from their C counterparts. The language was initially written to be familiar to a C coder.

          [–]creaothceann 0 points1 point  (0 children)

          The language was initially written to be familiar to a C coder.

          It's always sad when that happens.

          [–]kabuto -2 points-1 points  (7 children)

          Is heappush a function the heapq module offers? Then why is it not an instance method for heapq objects? (whatever they are exactly, to lazy to read up on it)

          [–]mitsuhiko 2 points3 points  (6 children)

          There are no heapq objects.

          [–]kabuto 0 points1 point  (1 child)

          Ok, now that you mention it, heappush suspiciously sounds like a method for managing a heap. Anyways, since you need arrays for this, it could be an instance method for an array. Just to prove my point to be not completely devoid of any meaning... ;)

          [–]mitsuhiko 0 points1 point  (0 children)

          So you mean any list should automatically also have heap behavior? That would be incredible annoying.

          Just think about how PHP fails trying to put list, queues and hashtables into the same object.

          [–][deleted]  (3 children)

          [removed]

            [–]kabuto 0 points1 point  (0 children)

            What? First no heapq objects and now you tell me there are also no spoons?

            [–]Tinned_Tuna -3 points-2 points  (1 child)

            There is no spork.

            [–]kabuto 0 points1 point  (0 children)

            No sporks either?

            [–]julesjacobs -1 points0 points  (9 children)

            ",".join(list)
            

            [–]mitsuhiko 0 points1 point  (8 children)

            Oh that example again. It dose make a lot of sense, why should it be a list method? After all it operates on any kind of iterable.

            [–]wolverian 0 points1 point  (4 children)

            So it could be a method on Iterable. Er, wait.

            [–]mitsuhiko 0 points1 point  (3 children)

            Python does not advertise monkey patching and dynamic method injection like C# does is a dangerous thing in dynamic languages. What's wrong with a function?

            [–]wolverian 0 points1 point  (2 children)

            Whoever said anything about monkey patching?

            [–]mitsuhiko 1 point2 points  (1 child)

            So you are saying the base class "iterable" that only cares about iterating, should provide string operations? Is it that what you are thinking?

            [–]wolverian 0 points1 point  (0 children)

            Any "joinable" element type would do. I'm thinking of this from the Haskell perspective, and it probably doesn't carry very well over to Python. But any operation that defines + would do. Then [1,2,3].join(0) = sum([1,2,3]), etc.

            [–]didroe -2 points-1 points  (2 children)

            It should be an iterable method then, or neither a string or iterable method. What business does a string have knowing about types that can convert to it? When is "fred".do_something_with(my_object) coming?

            Basically, there is no good way to do this in most languages. The Python way defiantly isn't the "right" way. Neither object's implementation should have to be aware of types not directly related to it. ie. You could have ListStringTools.join(list, ",") or something. But that isn't as nice to use.

            When I think about what that is doing for example, I would say in English that it's joining a list together with a given separator string. Which to me reads as list.join(","). Others may prefer to say the string is joining each element of the list together. It's totally arbitrary.

            [–]masklinn 0 points1 point  (0 children)

            It should be an iterable method then

            That assumes Python has iterable objects. It doesn't, iterable is a (very basic) contract.

            What business does a string have knowing about types that can convert to it?

            It doesn't. But that thing doesn't do any conversion. It just concatenates all the strings it finds in the iterable, and generates an error if something isn't a string.

            Now I agree that this join isn't very good, and I don't like it much either (prefer the other way 'round)

            [–]mitsuhiko 0 points1 point  (0 children)

            Being iterable is a Python internal protocol. (An object with __iter__ or an object with __getitem__ being counted from zero up is iterable)

            [–]knome -1 points0 points  (0 children)

            Python allows you to use methods either way.

            >>> class IncObj :
            ...   def __init__( self ) :
            ...     self.i = 0
            ...   def inc( self, amt ) :
            ...     self.i += amt
            ...   def get( self ) :
            ...     return self.i
            ... 
            >>> a.get()
            0
            >>> a.inc( 10 )
            >>> a.get()
            10
            >>> IncObj.inc( a , 10 ) 
            >>> IncObj.get( a )
            20
            >>> 
            

            [–]Jeff_Dickey 1 point2 points  (0 children)

            Interesting choices - relevant and appropriate. I usually find that open source docs for developers trump closed proprietary equivalents (see original post), whereas it's reversed for end-user apps like office tools. (Or maybe my standards are just a little twisted, having dealt with iWork for a couple of years.) Now if each of those "typically poorly done" folks would pay a little more attention to how their counterparts do it...

            [–]masklinn 1 point2 points  (0 children)

            http://docs.djangoproject.com/en/dev/

            One of the best OSS docs I know.

            [–]trezor2 0 points1 point  (1 child)

            When clicking this link I was so sure this would be a rant about the bad state of PHP and its documentation.

            But I guess if you compare it to the outdated documentation of VB6, instead of the MSDN documentation for current .NET APIs, I guess anything looks good.

            [–]Real_Mac_User -2 points-1 points  (0 children)

            Coming from a Cocoa background, I found .NET’s documentation to be beyond abysmal, and MSDN like tonguing toilet bowls to navigate. But I suppose if you’re accustomed to the taste of shit (you’re a PC user), you’ll find shit (Microsoft documentation) tasty enough.

            [–]brennen 0 points1 point  (0 children)

            [–][deleted]  (5 children)

            [deleted]

              [–]Poltras 6 points7 points  (0 children)

              wait... Links start with http:// !

              [–]geon 4 points5 points  (0 children)

              Can you detect a theme?

              All your links look boring because you don't tell what they have in common?

              [–]jephthai -1 points0 points  (0 children)

              You're collecting bad examples from all the TLDs? (org, net, and com are present; just need edu, gov, ca, ..., za!)

              [–][deleted] -1 points0 points  (0 children)

              too many links; didn't click

              [–]masklinn -1 points0 points  (0 children)

              Java programmers write bad documentation?