【问题标题】:PHP class constants seems to always be interpreted as stringsPHP 类常量似乎总是被解释为字符串
【发布时间】:2015-07-28 08:59:47
【问题描述】:

一个类常量似乎总是被解释为一个字符串,尽管它被定义为一个整数。为什么 PHP 会做这种类型的杂耍,我该如何防止呢?

见以下代码:

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 );

最后一行(构造函数的调用)抛出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

从回溯条目#0 可以清楚地看到,常量BitSet::FOO 作为字符而不是整数传递。因此,位掩码操作$flags & self::ALL !== $flags 不是在整数上执行,而是在按位 ASCII 表示上执行,因此失败。

什么鬼?!有没有比在任何地方都明确地使用(int)-cast 更好的方法来解决这个问题?

【问题讨论】:

  • 你不认为if( $flags &<-------需要成为&&
  • @Uchiha 不,这是按位与运算。这意味着“如果两个操作数中的位都为 1,则生成一个位设置为 1 的值,否则为 0”。
  • 我不确定为什么堆栈跟踪看起来像这样,但 var_dump 将其显示为 int:3v4l.org/mEYRZ

标签: php type-conversion class-constants


【解决方案1】:

我不太确定您的期望,但请注意 !==precedence& 更高,因此您在 1true 之间进行按位与运算。

你的意思是:

if( ($flags & self::ALL) !== $flags )

【讨论】:

  • 是的,就是这样。请参阅我自己的解决方案。在发布此问题半分钟后,我发现了这一点。 PHP 是...
  • @user2690527 是的,我认为这是问题所在,所以我用答案替换了我的评论。
  • 代码的意图对我来说似乎很清楚。我想如果您牢记运算符优先级,代码似乎显然是错误的,但这是一个容易犯的错误。
【解决方案2】:

对不起,这是我的错,我走错了方向。解决办法是

if( ( $flags & self::ALL ) !== $flags )

添加括号。 !== 运算符的优先级似乎高于 &

没有括号,首先将 sn-p self::ALL !== $flags 评估为 FALSE,然后评估 $flags & FALSE

PHP 是... :-(

【讨论】:

  • PHP 是……和这里的其他语言完全一样。
  • 多么甜蜜,这是语言的错,而不是坐在椅子上的那个人。因为这显然是 IT 的工作方式。
猜你喜欢
  • 2013-01-01
  • 2013-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-12
  • 2015-11-07
  • 1970-01-01
相关资源
最近更新 更多