0

私はこれを読みました:

次のエラーがあります。

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

はい。line 3014. のコードソースには、 function の前に/xx.class.phpいくつかのクラス宣言があります(要するに):fcXXX()

class P1 {
...
}

class P2 {
...
}

function fcXXX() {
}

だから私が得られないのは、致命的な「 」のPHP Fatal error: Cannot redeclare classにタイプ「 」のエラーがあるはずだということです。Cannot redeclare function php

さらに奇妙なのは、注意深く読むと、関数の宣言の最後で問題が発生することです。次の行を含むコードを次に示します。

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 }

2つの奇妙なこと:

  1. 関数には「include」や「require」などがないため、理論的にはこの種のエラーはあり得ません
  2. 3014は、行3007のエラーを発生させます(前の詳細なエラーを注意深く見てください)。

誰かがこの問題を抱えたことがありますか?それを解決するためにどこでチェック/テストする必要がありますか? (最適化の方法やコードの悪さについてコメントしないでください。これは私のものではなく、変更するつもりはありません)

4

1 に答える 1

2

おそらく、定義を再帰的にincludeまたはrequire-ingしています。オートローダーの設定はお済みですか?クラス定義ごとにファイルを作成したい場合があるため (できるだけ早く)、それらがどのように機能するか知っていますか。
このことを考慮:

//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_onceまたはを使用しますrequire_once。これにより、同じファイルを 2 回含めることを回避できます。

エラーの順序について:クラスを再宣言できないというエラーが発生する前に「関数を再宣言できません」
というエラーが発生する主な理由は、単にPHPがコードをコンパイルする方法にあると思います。 PHP は、もはやコードをそのままにしておくことはありません。あなたのコードはバイトコードにコンパイルされているので、それは...と言うべきか...プロセスでかなり変更されました 関数、 PHPがクラスの解析に進む前に解析する必要があります。なんで?これは単純に、PHP クラス メソッドも本質的には関数だからです。 それらはポインターを使用して呼び出され、メソッドを呼び出すときに、が渡され、 とともに、


zend_object_handlerszvalzend_class_entryzend_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実際に登録される前に名前の競合が発生することはありません (メソッドが重複していない限り)。

さらに、オブジェクト指向コードの適切なビットは、オートローダー機能を登録します。functionパーサーがそのキーワードから何を判断するかを知らなかった場合、オブジェクトは何になるでしょうか?
それだけではありませんが、クラスを再定義していることに気付く前に、関数を再定義しようとしている理由に PHP が気付くのはそのためだと思います。

Zendエンジンが関数/メソッドでどのように機能するかについてのより詳細な説明を含むいくつかの便利なリンクここあり
ます。について話している

于 2013-08-06T11:57:30.577 に答える