PHP致命错误:未知的typehint

时间:2014-08-25 13:07:09

标签: php yii php-5.5


public function evaluateExpression($_expression_,$_data_=array())
    {
        if(is_string($_expression_))
        {
            extract($_data_);
            return eval('return '.$_expression_.';');
        }
        else
        {
            $_data_[]=$this;
            return call_user_func_array($_expression_, $_data_);
        }
    }


我在此方法的第一行收到此错误。我在这里看不到任何类型。以上代码来自Yii Framework的内部文件。 (yiilite.php:L842)

错误是间歇性的,重启apache会修复它。无法重现错误。什么可能导致这个问题?无法弄清楚这一点。

最近有一点需要注意,这个错误只发生在使用Cache的Pages上。之前它会发生在每一页上。

我们正在使用memcached和opcache(PHP 5.5)。奇怪的是我们不需要清除memcached数据来解决问题,只有apache重启,这只会清除" opcache"。

1 个答案:

答案 0 :(得分:3)

错误

您看到此错误意味着PHP未在解释阶段失败,而是在执行阶段失败。您可能知道,PHP分两步执行 - 首先,将脚本编译为操作码,然后使用虚拟机(通常是ZendVM)执行这些操作码。因为我们可以确定它的执行阶段失败的原因在于zend_verify_arg_type(),这是执行实现的一部分:

static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC)
{
   //I stripped some lines here (insignificant)
   if (cur_arg_info->class_name) {
      /* do the things, when typehinted is class name */
   } else if (cur_arg_info->type_hint) {
      /* your case, typehint wasn't class name */
      switch(cur_arg_info->type_hint) {
           case IS_ARRAY:
               //I stripped some lines here (insignificant)
               break;

           case IS_CALLABLE:
               //I stripped some lines here (insignificant)
               break;

           default: //<---- You error is here
               zend_error(E_ERROR, "Unknown typehint");
       }
   }
   return 1;
}

正如您所看到的,为了发生此错误,PHP应将typehint视为而非类名,同时将其视为“未知”。这就是为什么你不能在常规情况下重现错误的原因 - 因为PHP会首先尝试将typehint视为类名(因此,错误将类似于“传递给{function()}的参数{N}必须是一个实例{classname}“

原因

所以,虽然你不能在正常的执行机制中得到这样的错误,你仍然可以得到一些损坏的编译文件 - 另一个提示是你正在使用opcache。因此,可能是因为您正在评估方法中的某些代码,这会导致编译文件损坏 - 但我无法肯定地说。另一件事 - 它可能是bug,它位于opcache扩展内。但无论如何,原因是 - 错误的编译导致VM尝试执行编译脚本时出现此类错误。并且,因为它可以通过清除opcache来解决(因此,web-server resart) - 我认为原因是 - 它是一个bug。

所以,TL; DR - 我不能说肯定的原因,但可以给出一些指导。由于这只是评论的过多,所以发布为答案