Reputation: 1881
A class constant always seems to be interpreted as a string although it is defined as an integer. Why does PHP do this kind of type juggling and how do I prevent it?
See the following code:
class BitSet {
const NONE = 0;
const FOO = 1;
const BAR = 2;
const ALL = 3;
public function __construct( $flags = self::NONE ) {
if( $flags & self::ALL !== $flags )
throw new \OutOfRangeException( '$flags = '.$flags.' is out of range' );
$this->value = $flags;
}
protected $value = self::NONE;
}
$bs = new BitSet( BitSet::FOO );
The last line (the invocation of the constructor) throws the OutOfRangeException
:
PHP Fatal error: Uncaught exception 'OutOfRangeException' with message '$flags = 1 is out of range' in test-case.php:12
Stack trace:
#0 /srv/www/matthiasn/class-constant-debug.php(19): BitSet->__construct('1')
#1 {main}
thrown in /srv/www/matthiasn/class-constant-debug.php on line 12
As you can clearly see from backtrace entry #0 the constant BitSet::FOO
is passed as a character not as an integer. Hence, the bit mask operation $flags & self::ALL !== $flags
is not performed on integers but on the bitwise ASCII representation and therefore fails.
What the hell?! Is there any better way to get this right than to do an explicit (int)
-cast everywhere?
Upvotes: 0
Views: 79
Reputation: 91742
I am not exactly sure what you expect, but note that !==
has a higher precedence than &
so you are doing a bitwise AND between 1
and true
.
Do you perhaps mean:
if( ($flags & self::ALL) !== $flags )
Upvotes: 3
Reputation: 1881
Sorry, it was my fault and I went into the wrong direction. The solution is
if( ( $flags & self::ALL ) !== $flags )
to add parentheses. The !==
operator seems to have a higher priority than &
.
Without the parantheses, first the snippet self::ALL !== $flags
is evaluated to FALSE
and then $flags & FALSE
is evaluated.
PHP is ... :-(
Upvotes: 1