簡體   English   中英

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

[英]“Cannot redeclare function” instead of “Cannot redeclare class”

我讀過這個:

我們有這個錯誤:

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

是。 line 3014 /xx.class.php的代碼源中,在函數fcXXX() 之前有一些類聲明,類似於(簡而言之):

class P1 {
...
}

class P2 {
...
}

function fcXXX() {
}

所以我得到的是,在致命的“ Cannot redeclare function php之前應該存在類型“ PHP Fatal error: Cannot redeclare class ”的PHP Fatal error: Cannot redeclare class

更奇怪的是,如果你仔細閱讀,問題就會在聲明函數結束時出現。 這是代碼行:

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 }

兩件奇怪的事:

  1. 在函數中沒有“包含”或“要求”或其他任何理論上不存在這種錯誤
  2. 3014行引出第3007行的錯誤(仔細觀察之前的詳細錯誤)。

有沒有人遇到過這個問題,在哪里檢查/測試來解決它? (請不要評論如何優化/代碼有多糟糕,因為它不是我的,我不會修改它)

可能遞歸地includerequire定義。 你有沒有設置自動加載器? 你知道它們是如何工作的,因為你可能想為每個類定義(ASAP)創建一個文件。
考慮一下:

//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...

要避免這種情況,請使用include_oncerequire_once 這樣可以避免兩次包含同一文件。

至於導致錯誤順序的原因:
在你得到錯誤之前得到錯誤“無法重新聲明函數”的主要原因不能重新聲明類 ,我認為,僅僅是因為PHP如何編譯代碼。
PHP不再保留您的代碼了。 你的代碼被編譯成字節碼,所以它......我們應該說...在這個過程中改變了很多
功能只需要被解析之前PHP可以繼續解析類。 為什么? 這很簡單,因為PHP類方法本質上也是函數。
他們使用被叫zend_object_handlers指針,調用方法時, zval傳遞,與allong zend_class_entry ,為了使zend_function能夠訪問所有的數據范圍(所有對象的屬性和方法,你有什么) 。 我不知道你的C知識是怎樣的,但如果你想測試它:

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

正如您在此處所看到的,為了使方法可以調用,必須定義所有zend_function 由於構造函數也是一個函數,我懷疑你的xx.Class.php文件中的所有函數都被解析了。 由於方法是在它們自己的(類)范圍內定義的,因此在實際注冊zend_object之前不能存在名稱沖突(除非有重復的方法)。

此外,任何體面的OO代碼都會注冊自動加載器功能 如果解析器不知道該function關鍵字的作用,那么對象會是什么?
還有更多不僅僅是那個,但我認為這一定是為什么PHP注意到為什么你在注意到你正在重新定義一個類之前重新定義一個函數的原因。

可以在此處找到一些有用的鏈接,其中包含有關zend引擎如何使用函數/方法的更詳細說明
保持帶有實際源的標簽總是有用的,這樣你就可以看到他們正在談論的代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM