drwxg62286 2013-08-06 11:03
浏览 22
已采纳

“不能重新宣布功能”而不是“不能重新宣布上课”

I've read this:

We have this error:

 PHP Fatal error:  Cannot redeclare fcXXX()
 (previously declared in /xx.class.php:3007) in /xx.class.php on line 3014

Yes. line 3014. And in the code source of /xx.class.php there are some class declarations before the function fcXXX(), something like (in short):

class P1 {
...
}

class P2 {
...
}

function fcXXX() {
}

So what I dont get is that there should be an error of type "PHP Fatal error: Cannot redeclare class" before the fatal "Cannot redeclare function php".

What is more strange, is that if you read carefully, the problem arises at the end of the declaration of the function. Here's the code with the lines:

3007 function fcXXX($p) {
3008     $a = strpos($p, '.');
3009     if ($a) {
3010         return trim(substr($p, $a+1));
3011     } else {
3012         return trim($p);
3013     }
3014 }

Two strange things:

  1. in the function there's no "include" or "require" or whatever so theorically there could not be an error of this kind
  2. line 3014 raises the error in line 3007 (watch carefully the detailed error before).

Has anyone ever had this problem, and where to check/test to solve it? (Please dont comment on how to optimize / how bad the code is, because it's not mine and I wont modify it)

  • 写回答

1条回答 默认 最新

  • dongma0722 2013-08-06 11:57
    关注

    You're probably recursively include or require-ing the definitions. Have did you set an autoloader? Do you know how they work, because you might want to create a file for each class definition (ASAP).
    Consider this:

    //index.php
    include('someFile.php');
    include('xx.class.php');
    
    //someFile:
    include('xx.class.php');//ERROR
    
    //or even worse, in xx.Class.php:
    include('someFile.php');//includes file that includes this file, which will include someFile again, which includes this file, which...
    

    To avoid this, use include_once or require_once. This avoids your including the same file twice.

    As to what causes the order of the errors:
    The main reason why you get the error "cannot redeclare function" before you get the error cannot redeclare class is, I think, simply because of how PHP compiles the code.
    PHP doesn't leave your code as is anymore. Your code is compiled to bytecode, so it's... shall we say... changed quite a bit in the process
    functions just have to be parsed before PHP can move on to parsing the classes. Why? that's quite simply because PHP class methods are, essentially, functions, too.
    They're called using the zend_object_handlers pointer, when calling a method, the zval is passed, allong with the zend_class_entry, in order for the zend_function to have access to all the data in scope (all the object properties and methods and what have you). I don't know how your C knowledge is, but if you want to test it:

    ZEND_API zval* zend_call_method(
        zval **object_pp,
        zend_class_entry *obj_ce,
        zend_function **fn_proxy,
        const char *function_name,
        int function_name_len,
        zval **retval_ptr_ptr,
        int param_count,
        zval* arg1,
        zval* arg2 TSRMLS_DC
    ) {
      int result;
      zend_fcall_info fci;
      zval z_fname;
      zval *retval;
      HashTable *function_table;
    
      zval **params[2];
    
      params[0] = &arg1;
      params[1] = &arg2;
    
      fci.size = sizeof(fci);
      /* fci.function_table = NULL;
       * will be read form zend_class_entry of object if needed
       */
      fci.object_ptr = object_pp ? *object_pp : NULL;
      fci.function_name = &z_fname;
      fci.retval_ptr_ptr = retval_ptr_ptr ? retval_ptr_ptr : &retval;
      fci.param_count = param_count;
      fci.params = params;
      fci.no_separation = 1;
      fci.symbol_table = NULL;
    
      if (!fn_proxy && !obj_ce) {
          /* no interest in caching and no information
           * already present that is needed later inside
           * zend_call_function.
           */
          ZVAL_STRINGL(&z_fname, function_name, function_name_len, 0);
          fci.function_table = !object_pp ? EG(function_table) : NULL;
          result = zend_call_function(&fci, NULL TSRMLS_CC);
      } else {
          zend_fcall_info_cache fcic;
    
          fcic.initialized = 1;
          if (!obj_ce) {
              obj_ce = object_pp ? Z_OBJCE_PP(object_pp) : NULL;
          }
          if (obj_ce) {
              function_table = &obj_ce->function_table;
          } else {
              function_table = EG(function_table);
          }
          if (!fn_proxy || !*fn_proxy) {
              if (zend_hash_find(
                  function_table, function_name,
                  function_name_len+1,
                  (void **) &fcic.function_handler) == FAILURE
              ) {
                  /* error at c-level */
                  zend_error(
                      E_CORE_ERROR,
                      "Couldn't find implementation for method %s%s%s",
                      obj_ce ? obj_ce->name : "",
                      obj_ce ? "::" : "", function_name
                  );
              }
              if (fn_proxy) {
                  *fn_proxy = fcic.function_handler;
              }
          } else {
              fcic.function_handler = *fn_proxy;
          }
          fcic.calling_scope = obj_ce;
          if (object_pp) {
              fcic.called_scope = Z_OBJCE_PP(object_pp);
          } else if (obj_ce &&
                     !(EG(called_scope) &&
                       instanceof_function(EG(called_scope), obj_ce TSRMLS_CC))) {
              fcic.called_scope = obj_ce;
          } else {
              fcic.called_scope = EG(called_scope);
          }
          fcic.object_ptr = object_pp ? *object_pp : NULL;
          result = zend_call_function(&fci, &fcic TSRMLS_CC);
      }
      if (result == FAILURE) {
           /* error at c-level */
           if (!obj_ce) {
               obj_ce = object_pp ? Z_OBJCE_PP(object_pp) : NULL;
           }
           if (!EG(exception)) {
               zend_error(
                   E_CORE_ERROR,
                   "Couldn't execute method %s%s%s",
                   obj_ce ? obj_ce->name : "",
                   obj_ce ? "::" : "", function_name
               );
           }
       }
       if (!retval_ptr_ptr) {
           if (retval) {
               zval_ptr_dtor(&retval);
           }
           return NULL;
       }
       return *retval_ptr_ptr;
    }
    

    As you can see here, in order for a method to be callable, all zend_function's must be defined. Since a constructor is a function, too, I suspect all the functions in your xx.Class.php file are parsed. Since the methods are defined within their own (class) scope, there can't be a name conflict (unless there are duplicate methods), before the zend_object is actually registered.

    Besides, any decent bit of OO code registers an autoloader function. What would an object be if the parser didn't know what to make of that function keyword?
    There's a lot more too it than just that, but I figure that must be why PHP notices why you're attemting to redefine a function before it notices you're redifining a class.

    A couple of useful links, containing a more detailed description of how the zend engine works with functions/methods can be found here
    It's always useful to keep a tab with the actual source at hand, too, so you can actually see the code they're talking about

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行
  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?