Live data from Hacker News

Stack Overflow: Defend PHP - convince me it isn't horrible

stackoverflow.com

61–70 of 74 posts

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#61
post #13

I'm spending most of my time maintaining a web application consisting of around 150k lines of PHP code. We (well - initially, it was just me) began development back in 2004 but since then the application has grown constantly. Back in 04, I already felt some reservations against PHP, but that's what I knew best and that's what was most used for the web (Rails might have been around, but not really known - other ruby o…

> What really disturbs me about PHP is its type conversion rules. 1 == '1' or even worse 'foobar' == 0, or '123n' == 123. This is cause for so many subtle bugs. Weird cases like 'foobar' == 0 are extremely rare and 1 == '1' is actually what you want most of the time. I've learned to embrace the type-less nature and use casts when I absolutely want to ensure a particular type. I no longer even consider this a problem.

The '123n'==123 conversion is the cause for at least 8 very nasty bugs in validating user input in that application I was referring to.

And the fact that when comparing integer to strings, PHP prefers to convert the string to compare instead of converting the number (which would be lossless)

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#62
post #61

Earlier quoted context omitted.

> What really disturbs me about PHP is its type conversion rules. 1 == '1' or even worse 'foobar' == 0, or '123n' == 123. This is cause for so many subtle bugs. Weird cases like 'foobar' == 0 are extremely rare and 1 == '1' is actually what you want most of the time. I've learned to embrace the type-less nature and use casts when I absolutely want to ensure a particular type. I no longer even consider this a problem.

The '123n'==123 conversion is the cause for at least 8 very nasty bugs in validating user input in that application I was referring to. And the fact that when comparing integer to strings, PHP prefers to convert the string to compare instead of converting the number (which would be lossless)

If you care about numbers in your application, wouldn't the very first test in validating user input would be an is_numeric() call?

In my opinion, you have to be doing a lot of other things incorrectly for this to be a real problem.

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#63
post #61

Earlier quoted context omitted.

The '123n'==123 conversion is the cause for at least 8 very nasty bugs in validating user input in that application I was referring to. And the fact that when comparing integer to strings, PHP prefers to convert the string to compare instead of converting the number (which would be lossless)

If you care about numbers in your application, wouldn't the very first test in validating user input would be an is_numeric() call? In my opinion, you have to be doing a lot of other things incorrectly for this to be a real problem.

is_numeric doesn't help you if you want to find out whether the value in $foobar is a string that represents an integer or not.

The only way to safely do that in PHP is, sadly, a regular expression.

is_int checks the type, so is_int('1234') is as false as is_int('123n') or is_int('abc')

is_numeric is too permissive as it allows floating point numbers or even hexadecimal values.

intval($foobar) == $foobar doesn't work due to intval('123n') == 123

intval($foobar) === $foobar naturally doesn't work because the types don't match.

The code in question is the receiving end of some machine generated communication that is supposed to closely follow a specification.

During validation if the spec says that it requires a base10 integer encoded in ASCII, then 0xFF isn't permissible just because is_numeric() says so.

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#64
post #63

Earlier quoted context omitted.

If you care about numbers in your application, wouldn't the very first test in validating user input would be an is_numeric() call? In my opinion, you have to be doing a lot of other things incorrectly for this to be a real problem.

is_numeric doesn't help you if you want to find out whether the value in $foobar is a string that represents an integer or not. The only way to safely do that in PHP is, sadly, a regular expression. is_int checks the type, so is_int('1234') is as false as is_int('123n') or is_int('abc') is_numeric is too permissive as it allows floating point numbers or even hexadecimal values. intval($foobar) == $foobar doesn't work…

I have this function in my own code. You can adjust it's permissiveness your taste:

    function is_intval($value)
    {
	if (is_integer($value)) return true;
	if (is_bool($value)) return true;
	if (!is_numeric($value)) return false;
	if (is_float($value) && floatval(intval($value)) == $value) return true;
	if (is_string($value) && strval(intval($value)) == $value) return true;
	return false;
    }

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#65
post #63

Earlier quoted context omitted.

is_numeric doesn't help you if you want to find out whether the value in $foobar is a string that represents an integer or not. The only way to safely do that in PHP is, sadly, a regular expression. is_int checks the type, so is_int('1234') is as false as is_int('123n') or is_int('abc') is_numeric is too permissive as it allows floating point numbers or even hexadecimal values. intval($foobar) == $foobar doesn't work…

I have this function in my own code. You can adjust it's permissiveness your taste: function is_intval($value) { if (is_integer($value)) return true; if (is_bool($value)) return true; if (!is_numeric($value)) return false; if (is_float($value) && floatval(intval($value)) == $value) return true; if (is_string($value) && strval(intval($value)) == $value) return true; return false; }

... hereby proving my point that PHP's default conversions are a bit... strange.

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#66
post #13

I'm spending most of my time maintaining a web application consisting of around 150k lines of PHP code. We (well - initially, it was just me) began development back in 2004 but since then the application has grown constantly. Back in 04, I already felt some reservations against PHP, but that's what I knew best and that's what was most used for the web (Rails might have been around, but not really known - other ruby o…

> What really disturbs me about PHP is its type conversion rules. 1 == '1' or even worse 'foobar' == 0, or '123n' == 123. This is cause for so many subtle bugs. Weird cases like 'foobar' == 0 are extremely rare and 1 == '1' is actually what you want most of the time. I've learned to embrace the type-less nature and use casts when I absolutely want to ensure a particular type. I no longer even consider this a problem.

You want '0' == 0 and ' 0' == 0. But you also get

  '0' == false
  array('0' => 'x') == array(false => 'x')
  ' 0' == true
  array(' 0' => 'x') != array(true => 'x')
which isn't even an equivalence relation. I have to try this or look it up every time I run into it, because it doesn't make any damn sense.

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#67

Earlier quoted context omitted.

A well designed language or library can decrease the likelihood of specific bugs, and especially security problems. Imagine the existence of a library which made it easier to use SQL placeholders than to concatenate user input into a string. Imagine PHP without register globals.

PHP already does that via PDO. PHP's "Register globals" was deprecated exactly one year ago, in 5.3.0.

That was exactly chromatic's point---language design and features do make a difference.

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#68
post #67

Earlier quoted context omitted.

PHP already does that via PDO. PHP's "Register globals" was deprecated exactly one year ago, in 5.3.0.

That was exactly chromatic's point---language design and features do make a difference.

It's always easier to blame the tool for your failed craft than it is to be a good programmer, isn't it :)

Putting PHP in the "inadequate corner" or trying to convince oneself that it is lacking in features is just an easy excuse.

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#69
post #65

Earlier quoted context omitted.

I have this function in my own code. You can adjust it's permissiveness your taste: function is_intval($value) { if (is_integer($value)) return true; if (is_bool($value)) return true; if (!is_numeric($value)) return false; if (is_float($value) && floatval(intval($value)) == $value) return true; if (is_string($value) && strval(intval($value)) == $value) return true; return false; }

... hereby proving my point that PHP's default conversions are a bit... strange.

I never said it wasn't weird!! I just said that it's not really a practical problem in most cases. Perhaps you do have to be extra careful and I'm just so used to it that I don't give it a second thought.

Re: Stack Overflow: Defend PHP - convince me it isn't horrible

#70

Earlier quoted context omitted.

> What really disturbs me about PHP is its type conversion rules. 1 == '1' or even worse 'foobar' == 0, or '123n' == 123. This is cause for so many subtle bugs. Weird cases like 'foobar' == 0 are extremely rare and 1 == '1' is actually what you want most of the time. I've learned to embrace the type-less nature and use casts when I absolutely want to ensure a particular type. I no longer even consider this a problem.

You want '0' == 0 and ' 0' == 0. But you also get '0' == false array('0' => 'x') == array(false => 'x') ' 0' == true array(' 0' => 'x') != array(true => 'x') which isn't even an equivalence relation. I have to try this or look it up every time I run into it, because it doesn't make any damn sense.

From the documentation: "A key may be either an integer or a string" So your boolean true is converted to the integer 1 and your boolean false is converted to the integer 0. Dump those arrays and you'll see they don't contain boolean keys. Then it's just a simple matter of '0' == 0 and ' 0' != 1. It's all perfectly logical.
Post reply on HN