PHP messiness: zero isn’t false, or is it?
Sterling Camden
Several years ago, Gary Hart said something that has stuck with me ever since: “just because it’s messy doesn’t mean you don’t want to do it.” We were discussing plans for driving throughout the UK while there on business — but time and again I find this principle applies to other situations as well. Besides the obvious, um, recreational possibilities, I can think of many more: eating sloppy sandwiches, parenting, electing public officials, starting a relationship, and coding in PHP.
PHP powers a lot of the web, including such popular frameworks as WordPress, so you really need to have it in your programming portfolio. But it’s a messy language. I’m not just talking about the way that PHP tends to sprawl like semicolon-laden vines around your HTML, earning an alternative interpretation of “Page Hacked to Pasta”. Nor am I referring (this time) to its sucky object model. The language itself contains many little gotchas and “almost right”s that wait like snares for the feet of the unwary coder.
One I ran into yesterday (not for the first time) is PHP’s partial distinction between false and zero. In PHP, false is boolean, and zero is numeric. Fine and good. But if you treat a zero value as a boolean expression, the zero gets converted to a boolean false.
This seems innocent and helpful enough until you get to a function like strpos, which returns the position of one string within another. If the target is not found in the source, it returns boolean false. So, to make sure that one string doesn’t contain another, you’d think you’d do something like this:
if (!strpos($source, $target))
But there’s a problem here. If $target starts at the beginning of $source, strpos will return 0. Because it’s in a conditional, that gets converted to boolean false, and the test passes. So, you need to explicitly test for false instead, right?
if (strpos($source, $target) == false)
Wrong. Because you’re comparing it against a boolean value, the zero still gets converted to a boolean false. The only right way to do this is:
if (strpos($source, $target) === false)
The triple equal sign tells PHP to only evaluate to true if both operands have the same type and the same value, so no conversion takes place. Granted, the PHP docs have a great big warning on strpos to this effect, but the net result is something less than intuitive coding.
Languages like Java and C# solve this problem by not allowing automatic conversion between numeric and boolean values. That’s sort of like castrating the entire population to prevent birth defects. So why doesn’t this create problems for other languages?
In Synergy/DE, indices start at 1, so the instr function returns zero for not found:
if (!instr(1,source, target))
Quite logical and linguistically elegant (except for having the starting index as the first parameter), but then you don’t get to have the secret handshake.
Even though Ruby uses a starting index of 0, it prevents confusion in routines like String#index by returning nil instead of a number for not found. Zero is treated as an object — and thus is not false — while nil does evaluate to false. Thus,
print "good" if ("abcde".index("a"))
print "bad" if ("abcde".index("f"))
prints “good”, even though the index of “a” within “abcde” is 0. Why should 0 be false anyway?
In C and C++, indices start at 0, and 0 can be used as a stand-in for false (in fact, all falses are zero), yet I hardly ever make the mistake of “if (strpos(…))” in C. Why? Because the documented return value for “target not found” isn’t FALSE, it’s -1. I immediately know that to test for this return value I must say:
if (strpos(source, target) < 0)
The significance of the result does not rely on a distinction between returned values that can be automatically converted from one to the other. PHP, on the other hand, requires the programmer to explicitly prevent that conversion from happening. Automatic conversions are supposed to be a convenience for the programmer, not a trap.
Maybe PHP stands for Purposely Hampers Programming.
Posted in C and C++, C#, Java, PHP, Ruby, SynergyDE, Wildly popular |
52 Comments » RSS 2.0 | Sphere it!




print “good” if (“abcde”.index(“a”))
Please, do us a favour and not use the ()
It looks like lisp, but ruby is a lot cleaner than lisp
And PHP sucks so much that I will never again use it unless it would mean I get paid for it (which means, for my personal needs, I have switched to ruby entirely.)
PS: I think Matz should focus on a ruby-vs-php because even though PHP as a language sucks, it has some great applications like phpbb. These things would be so COOL if they could be rewritten in ruby WITHOUT needing something like rails!
> Languages like Java and C# solve this problem by not allowing automatic conversion between numeric and boolean values. That’s sort of like castrating the entire population to prevent birth defects. So why doesn’t this create problems for other languages?
C# returns -1 if the string isn’t found, giving you:
if ( source.IndexOf(target) == -1)
No magic needed.
Sorry, shes, I love my parentheses
Right, Jonathan, in the case of IndexOf the test is just as sane (but not any saner) than C’s strpos. I prefer a language where you can have a string search function return a result that can be evaluated as true/false, and at the same time as an index. Ruby and Synergy/DE meet that desire. C#, Java, and C require a comparison operator and another numeric operand. PHP is the most insane case, requiring a comparison operator against a boolean operand.
Ruby can be used instead of PHP without resorting to Rails. You just have to use CGI and/or eRuby instead, generally, unless you run your own webserver.
There are other Ruby web frameworks out there, too. Camping is a much simpler framework, designed by Why the Lucky Stiff (of “Why’s Poignant Guide”). Getting them on your webserver is up to you, unfortunately — mod_ruby is far less common than mod_php on shared hosting providers.
With a webhost that provides Rails, you should be able to get eRuby working too (as I have on Bluehost). That provides some behavior similar to what you get with mod_php, allowing you to embed Ruby in XHTML for a web templating language effect — the only downsides being that eRuby itself will be running as a CGI process and including material from additional files is a bit less simple and easy with eRuby than mod_php.
If you read the function description it tell you that it returns the starting position of what you are searching for, and its starts at 0, so 0 will never be false, because false is only returned if there is no match if you are searching for “mo” in the string “montana”, 0 will be returned because 0 is the position in the string where mo starts.
Its actually quite simple if you read the docs.
The documenation further states:
This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE, such as 0 or “”. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
SO RTM AND use binary comparason when checking for boolean values.
Donald, I read the docs and understood them. Thanks for assuming that I’m an idiot. Most of the time you’d be right, but not this time.
My point is that it’s bad language design. A numeric zero gets automatically converted to a boolean false when used in as a boolean expression. So its a trap door for the programmer. It’s just one more thing you have to be aware of, which is not what a good compiler does for you.
Yes but look at it this way its based on position, and position always starts at 0 in php, so converting 0 to boolean false would be wrong
My point exactly, Donald. The fact that PHP converts 0 to boolean false is the source of this whole problem. OR, if it returned -1 for not found instead.
This is a feature which once mastered can be exceptionally powerful, yes sometimes it is annoying but more often then not it makes life easier.
I remember looking at PHP and saying YUCK! along time ago, now to me it is just another handy language to know with some pretty neat features.
If you don’t like it fine, if you don’t understand it fine, but to bitch about it because it is unfamiliar to you is silly.
@shes
How would one app be any better in another language if the interface, functionality and presentation is the same ?
You really need to step outside the ‘fanboi’ box, syntax in the end means squat what is important is the solution to the problem.
“Maybe PHP stands for Purposely Hampers Programming.” I am sorry for telling this, but “Maybe you are a moron”.
Read the documentation and stop complaining, PHP is a loosely typed programming language. Once you start having experience with PHP it goes very well. All languages have their strange gotchas, another one in PHP is the global variables, like:
$gl_var = 1;
function my_func(){
print $gl_var; // it’s not visible here
}
You have explicitly to say global $gl_var; of $_GLOBALS['gl_var']
But this doesn’t mean that the language sucks
Anonamoose and Alan: if you really think that the language you use has no effect on your productivity, then I guess you’ve never used Ruby.
I use PHP a lot — but I certainly feel entitled to bitch and moan about the things it does wrong.
I didn’t say it has no effect, but once you learn the syntax and particularities it will be just a different syntax from other language.
I agree you can say whatever you want.
But it could be the same thing in a C program. If you do a if(0) “0″ is a false, the difference in a C program if you do a strchr() it returns a pointer, in the case of PHP it’s the index.
“C# returns -1 if the string isn’t found, giving you:
if ( source.IndexOf(target) == -1)
No magic needed.”
And if you try
if ( source.IndexOf(target) )
You get a compile error. It’s idiot proof
I agree with you that you can get used to any syntax. If you use it long enough, you can even get to thinking that it’s the best syntax possible.
For someone like myself who codes in many different languages (and even helped design a few), the insanity of having a function that returns false for failure but also returns a non-failure case that gets automatically converted to false in a boolean test is perhaps more glaring.
And I’m not saying that PHP is the only language to make such idiotic decisions on syntax. The 0 return of C’s strcmp and related functions, which also evaluates to FALSE, is almost as bad.
@Danny: yes, C# keeps you from hurting yourself. But I like Ruby’s approach better, where you can still use the function return as a boolean expression, and it works just as you’d expect.
Hey, Sterling . . . are you still grateful I reddited this? I see that the PHP-fans have come out of the woodwork to call you a heretic (well, a “moron”, anyway). I’m particularly amused by the fact that they’re telling you that your “problem” is just that you aren’t familiar with PHP (which I happen to know is a patently false assumption in your case). My favorite part of the responses you’ve gotten so far is the tendency of some respondents to essentially confirm everything you’ve said, but to do so in a manner that makes it sound like they’re contradicting you and trying to teach the slow kid a lesson, all the while trying to put some positive spin on the atrocious boolean test behavior built into PHP.
Maybe in a near-future ITSEC post I should tackle other subjects related to the piss-poor design standards of PHP, like the (last I checked) still unaddressed ability to produce buffer overflows with an extremely long URL, just to see if I can draw some of the heat off you for a while. I think my next at ITSEC will be about Ruby for portknocking, so it’s not like I’m not angling toward more coding security topics anyway. Could be fun, especially since the Powers That Be at TR seem to like controversy. Then again, my recent commentary at SOB about how PHP has given markup embedded templating a bad name doesn’t seem to have siphoned off any of your PHP trolls.
’s OK, apotheon — I like the heat, it cooks up the Google juice.
A lot of what’s been said makes me think that these people haven’t used many other programming languages. If you’ve only ever seen Java and PHP, then PHP doesn’t look so bad.
I’m planning to link to your post in the near future. Seems like it’s taking me forever to get my link posts done anymore.
I’d be interested to read about security risks in PHP. After all, I use it for both of my blogs!
No such thing as bad publicity, I guess.
I’ll have to hunt down some information on that PHP flaw again, and find out whether it’s still exploitable.
I normally don’t take troll bait although I will on this occasion
@apotheon
You make a nice straw man argument about all of us “PHP-fans” even though you really have no idea who we are, well done you have shown that you have a mature mindset and lateral thinking ability.
Now hmm lets see, PHP’s “piss-poor design standards” yes PHP is not the most eloquent language and you can recite many examples of how it basically takes function names, parameter order and ideas from other languages and mashes them up.
Taking the “heat” from all of us PHP zealots, wow your a knight in shining armour maybe one day you can save a kitty in a tree too and get your photo taken and be famous.
So what does this get you? nothing, the original assertion of 0 == false being bad is bogus and stating that everyone should go do it the rails way just because you know better then everyone else and because you are really just that good is like winning the special Olympics.
As for pointing out PHP has a flaw well wow, I’m so glad rails has never had a single bug in it’s existence and that if one does exist it won’t count … just ’cause’.
You need to grow up, there is no “them” and “us” in programming, there are languages that suit situations and there are zealots who refuse to accept knowing syntax is not programming.
Welcome to the real world.
P.S. Looks like I’m not the only one who figured out that you should use the tool that suits.
I stumbled across something relevant to your link that you might want to read: Big Requirements Up Front
It’s the best analysis of the circumstances of your link’s backstory that I’ve seen so far, from the point of view of someone that knows that if you can’t get a good product using an even halfway usable tool in two years of development, there’s something much more wrong with your project than the tools you’re using — unless you really are using the wrong tool. In this case, however, they were trying to use the right tool, or at least one that wasn’t wrong per se: a web application framework for developing web applications. No, the wrong tool in this case would be something more like Frontpage, or perhaps a soldering iron.
If you wanted to make an exception to that rule, you should be responding to the PHP trolls — not to me.
I can’t help it if you choose to lump yourself in with people like “Alan”, who very maturely suggested that Sterling was a moron for having the gall to observe that PHP is imperfect. If the shoe fits, wear it. If not, perhaps you should learn to avoid assuming every statement everyone makes is a personal attack specifically aimed at you.
The irony of this statement following your comment about troll bait is palpable.
. . . until you spend forty-five minutes developing a work-around when you run into an edge-case. Suddenly, it becomes quite real, relevant, and significant.
1. You seem to know so little about other languages that you cannot differentiate between Rails (a web development framework) and Ruby (a language).
2. Nobody said everyone should do it the Rails way, or even the Ruby way.
OCaml and Perl 6 both have alternative good ways to handle it, and Ruby’s would be entirely inappropriate to certain types of statically typed languages. On the other hand, it’s a darn sight better than PHP’s way of handling boolean values, where someone apparently said “Let’s keep Perl’s context based system of handling boolean tests, but make it worse by trying to emulate it with an immediate cast to an actual boolean type.” While Perl’s means of handling boolean tests based on contextual evaluation is somewhat broken for many cases, it at least doesn’t actually change data types based on the operator.
. . . assuming you don’t simply subscribe to the notion that data in PHP is entirely typeless (which would be something akin to debate suicide if you’re trying to defend PHP).
You seem to have completely overlooked the salient point in bringing up that flaw.
Are you simply unaware that Rails isn’t a language?
There wasn’t any “them” and “us” in programming here until others started declaring Sterling a moron for pointing out some warts on PHP’s nose and you decided to throw in your lot with them.
Non sequitur, much?
PS: Rails is a framework, not a language. Derek Sivers seems to understand this. I don’t know why, after reading his account of why a specific framework wasn’t suited to his task, you don’t understand this.
I’m no language zealot. I use many different languages, including PHP. And yes, they all have warts or gotchas. The fact that I pointed out one of PHP’s worst features doesn’t mean that I don’t think it has any place in software development. Heck, even COBOL still has a place in software development.
I’m not about to try to sit down and rewrite any major piece of software just because the language (or the framework) employed has flaws. I’ve known many companies that attempted just that, only to give up the project after many thousands of dollars were thrown at it.
My point in this post is not to try to get everyone to rewrite in Ruby. It’s to make people aware of the consequences of choosing a particular language, and hopefully to help language designers avoid such pitfalls in the future.
I’m still waiting to see how it is the worst feature, it is actually a great feature that I use all the time.
As for calling him a moron well that was immature and at no point did I or do I think he is a moron, I don’t know the guy!
The one thing I can garner from this article and even your response is that both of you are definitely not open to the idea that your wrong and well you are, spouting straw man arguments about all the bad things in PHP that prove this is as useful as tits on a bull and can not magically make it true.
As for the whole rails/ruby thing yes I use them interchangeably, is it bad yes it is, why do I do that because I never hear of anything that is written in ruby that isn’t rails based (I do realise the language was around before the framework).
As for the languages I’m familiar with (I’m no PHP zealot just hate FUD) scheme, lisp, c, c++, java, PHP, python to name the main ones I even dabbled with c# and yes ruby/rails.
So yes I can see this ‘feature’ is not obvious but in the realm of web engineering it is actually a powerful feature, why don’t you file a bug report if you hate it so?
There’s no use filing a bug report because it was designed that way. That is my only objection. Bad design. I will still use PHP where it makes sense to use it. But I don’t have to like this feature of the language, nor do I have to admit that it’s “a great feature” to not be able to use a return value in a conditional without first insuring that it doesn’t get automatically converted from one type to another.
I keep forgetting I can just reply to a specific comment here. Sorry ’bout my overly-linear response ordering, Sterling. I’ll try to remember to do better in the future.
NP, I just added the Brian’s Threaded Comments plugin over the weekend.
After your first threaded comment to me, I figured I’d start responding in threaded comments — then promptly forgot. Several times.
Obviously, however, I have started to learn. By the way, I like the way the plugin’s working for you so far. The thinly-margined nested box appearance of it works well for showing the threaded relationship of replies without taking up too much horizontal screen real estate. This and reddit’s comment threading are two of the best implementations of threaded discussions I’ve seen, in terms of appearance, space-saving, and intuitive usability.
. . . and, of course, TR’s is still one of the worst. They seem to be locked into their Java-based discussion forum software, though.
The one thing I wish it had, which TR does somewhat well, is show me which of the threaded comments I haven’t yet read. Not sure how something like that could even be implemented, just wishing.
It’s not. I direct your attention again to what Sterling actually said: “one of PHP’s worst features”
One of the worst. Not “the worst”. Just as you seem to have difficulty differentiating between Ruby and Rails, you seem to have difficulty differentiating between general and specific.
I’m completely open to the idea that I’m wrong about something. Show me some compelling evidence, and I’ll consider it just like all the other compelling evidence I’ve seen. I find it ironic that you’ll just apply a blanket assumption that people who disagree with you are wrong and unwilling to keep an open mind, however, particularly when your entire argument seems to consist of comments that while others have laundry lists of technical problems with a given language misfeature it works just fine for you.
I’m not convinced you know what a straw man fallacy actually is. A straw man is an assignment of an argument to the opposition that the opposing party does not actually support, in an attempt to divert the debate to ground where you have surer footing, as opposed to addressing the opposing arguments that were actually made. For example, claiming that Sterling and/or I have specifically advocated Rails over PHP, stated that Ruby’s means of dealing with boolean tests is right for everyone in every case, or claim that the boolean testing problem is the worst problem with PHP, so that you can attack those positions rather than the positions we have actually taken — these all qualify as straw man fallacies.
Expressing just how little experience you have with Ruby at all (apparently, “none at all aside from reading about Rails somewhere”) doesn’t help your argument even a little bit. All it does is convince people that you don’t know what you’re talking about when you say that PHP’s means of handling boolean tests is no worse (and possibly better) than Ruby’s. You clearly have no experience with the boolean test scheme Ruby uses on which to base your conclusions.
Regardless of that, however, the differences between frameworks and languages in general are significant, such that comparing Rails with PHP is like comparing apples and oranges. No, that’s not quite right — it’s more like comparing mangoes and a 1967 VW bus.
Perhaps you’re not aware of this, having never used Ruby itself, but dabbling in Rails doesn’t really require any useful knowledge of Ruby.
It’s not a bug. It’s a misfeature.
. . . and I don’t “hate” it. I just dislike it.
Hmm… I wonder what might qualify as the worst feature of PHP?
The community.
ouch!
That’s not actually all that unusual. There are a lot of languages out there whose communities leave something to be desired, in my experience. Ruby and Perl both have excellent communities. C and C++ have scatterings of people that at points sometimes look like communities, and are at least useful. Some languages have nothing that looks at all like a community. Some are downright unappetizing, but are something of a necessary evil.
PHP’s community, however, is in my experience an unnecessary evil. It is endured the same way as some of those that are a necessary evil, but it doesn’t really provide enough value to the independent PHP coder to make it worth one’s while to get involved.
Of course, that’s just one man’s opinion. Your mileage may vary.
[...] of the deficiencies of PHP, another one is the complete lack of built-in debugging capabilities. Sure, you can find [...]
Wow a mistake (saying ‘the’ not ‘one of’)and you guys take it to mean the earth, nice you both get cookies for your effort.
I especially like how you character assassinate me over my inexperience with ruby, yes I am a complete non-thinking moron due to not having used ruby for an extended period of time.
As for if I used ruby itself read up, yes I actually used ruby not just rails, just because of your nit-picking of ruby/rails does not magically make me a dumbass, sure I’m not an expert in the language but I can honestly say that it certainly did not impress me enough to keep using it.
And …
Wow nice leap there, do you know me? have you placed cameras in the light bulb in my office? Have you got some form of logging program on my PC that tells you what I read ?
So in other words what you stated are bold faced lies in an effort to support the “your wrong and I’m right because I’m the best” attitude you seem to have.
Anyway I’m happy for you to have an opposing opinion and I’m not about to make some jackass lies and twist what is written (like others have) in some attempt of being right so no more posts from me, life is to short for this kind of crap.
Feel free to see this as a victory as I’m sure you will.
It’s nice how you can put words in my mouth and just invent things whole cloth against which to argue. You don’t even need me here, especially since you’re ignoring what I actually did say. You can have this entire flame war of yours without me.
Nope. I made an assumption. I usually don’t make assumptions like that, but I figured I’d be nice this time and assume you were inexperienced with Ruby rather than simply incapable of learning from experience.
I don’t think you know what a “lie” is. See, for me to be lying, I’d have to know you used Ruby, the language, rather than just Rails, the framework, and intentionally make a statement to the contrary. This sort of inability to differentiate between things like “lie” and “assume” may help to explain many recent examples of your inability to make valid points.
No, you’re not “about to”. You already have.
I don’t see it as a victory. I see it as a waste of time I probably should have avoided. You haven’t offered a single useful piece of evidence of anything new I might learn. You’ve just declared me wrong, and blamed our failure to disagree on what you imagine is my psychological dysfunction based on your no doubt several graduate degrees from prestigious universities in various fields of social sciences, qualifying you to diagnose my behavior so well.
Wonderful article. Just led me to debug a function tasked to get something from the database, after some data manipulation. Returns false when failed, an integer when successful, and apparently it was working well and returning zero – the correct value, after all.
@apotheon
There really exist people who are so paranoid thinking all statements are “attacks to him” and just think there are only two sides of things, you vs. me, good vs. bad. Forgive him, he knows not what he is doing
Thanks for the perspective, azure_ardee. I’ll try to keep that in mind for the future.
Thanks, azure_ardee — glad to know that it helped.
[...] good example of a Simon Says Rule in programming language design is PHP’s test for failure on strpos. You have to remember that you can’t say in effect, “is the result [...]
When you don’t know what you are doing, do it neatly.
—————————————————————————————————-
http://xanga.com/efrainlindsayff
Are you saying that messy language constructs are a sign of genius?
Maybe it’s just advice.
[...] If you picked the giraffe, you’re a PHP person. Like the giraffe’s neck, it has a feature specially crafted for every purpose — provided you can remember its name and whether it returns an integer, a boolean, or both. [...]
[...] the code that is within those delimiters. That code is Perl-like – but much simpler and less consistent, betraying a history that contains more evolution than intelligent design. Hundreds of [...]
I’m a C# developer, so of course I’ll be biased with my opinion, but I really do think that C# has the best syntax for this particular example.
All of your examples above are conditionally calling code if a source string contains a target string, but never actually using the index returned, so why not just do this?
if (source.Contains(target))
{
// code
}
Simple, logical, and no ambiguity. If you did need the index, I’d probably do something like this:
int index;
if ((index = source.IndexOf(target)) != -1)
{
// use index here
}
C# certainly does better than PHP here, but my favorite from the above is Ruby’s implementation:
if source.index(target)
# do something
end
or if the index is required:
if index = source.index(target)
# use index here
end
Even if index is 0, you don’t get a false if the string is found — because zero isn’t false.
Oh, and if you like a more English-like verbiage or a strict Boolean return value use String#include?:
if source.include? target
# do something
end