2

ツールが存在する場合、または 5 分以内で書き込める場合はツールが必要です (誰の時間をも無駄にしたくありません)。

問題のツールは、PHP スクリプトの include、require、include_once、require_once を解決し、実際に then の内容を再帰的にハードコーディングします。

これは、複数のインクルード ファイルのコードとリソースを実際に使用する 1 つの大きなファイルで PHP スクリプトを出荷するために必要です。

PHP が CLI スクリプトに最適なツールではないことはわかっていますが、PHP を最も得意としている私は、PHP を使用して個人用または半個人用のツールを作成しています。PHP以外のものを使用したり、何か他のことを学ぶように指示する、役に立たない回答やコメントは必要ありません

このアプローチのアイデアは、個人用ディレクトリに配置するために必要なすべてを表す単一のファイルを~/.bin/作成し、完全に機能する自己完結型のスクリプトとしてそこに保存できるようにすることです。スクリプトにインクルード パスを設定して、XDG データ ディレクトリの標準などを尊重するものに設定できることはわかっていますが、そのアプローチを試してみたかったのです。

とにかく、車輪の再発明をしたくなく、すべての検索で何も得られなかったので、そこで尋ねますが、ここで洞察がない場合は、私が行っていた方法で続行し、実際にツールを作成しますこれにより、includes と requires が解決されます。

助けてくれてありがとう!

PS: 例を含めるのを忘れたので、メッセージを言い換えたくありません: これらの 2 つのファイル
mainfile.php

<?php
    include('resource.php');
    include_once('resource.php');
    echo returnBeef();
?>

resource.php

<?php
    function returnBeef() {
        return "The beef!";
    }
?>

として「コンパイル」されます(明確にするためにコメントが追加されました)

<?php

    /* begin of include('resource.php'); */?><?php
    function returnBeef() {
        return "The beef!";
    }
    ?><?php /* end of include('resource.php); */
    /*
    NOT INCLUDED BECAUSE resource.php WAS PREVIOUSLY INCLUDED 
    include_once('resource.php'); 
    */
    echo returnBeef();
?>

スクリプトは明示的なコメントを出力する必要はありませんが、出力できれば便利です。

助けてくれてありがとう!

編集1

スクリプトに簡単な変更を加えました。自分でツールを書き始めたので、元のスクリプトに誤りがありました。インクルード ファイルは、最小限の作業を行うために、開始タグと終了タグ ( <?php ?>)で囲む必要があります。

結果のスクリプト例は結果として変更されていますが、テストされていません。

編集2

スクリプトは、実行時の正確な解析のように、PHP スクリプトの負荷の高い解析を実際に行う必要はありません。単純なインクルードは処理するだけで済みます (include('file.php'); など)。

私は自分のスクリプトの作業を開始し、ファイルを読み取って<?php ?>、コメントや文字列ではなく、タグにのみ含めるように無意識に解析しています。小さな目標はdirname(__FILE__).""、インクルード ディレクティブで検出し、実際にそれを尊重できるようにすることです。

4

2 に答える 2

2

興味深い問題ですが、実行時の詳細な知識がなければ実際には解決できない問題です。条件付きインクルードを決定することはほとんど不可能ですが、十分に単純な仮定を行うと、おそらく次のようなもので十分でしょう:

<?php
  # import.php 
  #
  # Usage:
  # php import.php basefile.php
  if (!isset($argv[1])) die("Invalid usage.\n");

  $included_files = array();

  echo import_file($argv[1])."\n";

  function import_file($filename)
  {
    global $included_files;

    # this could fail because the file doesn't exist, or
    # if the include path contains a run time variable
    # like include($foo);
    $file = @file_get_contents($filename);
    if ($file === false) die("Error: Unable to open $filename\n");

    # trimming whitespace so that the str_replace() at the end of 
    # this routine works. however, this could cause minor problems if
    # the whitespace is considered significant
    $file = trim($file);

    # look for require/include statements. Note that this looks
    # everywhere, including non-PHP portions and comments!
    if (!preg_match_all('!((require|include)(_once)?)\\s*\\(?\\s*(\'|")(.+)\\4\\s*\\)?\\s*;!U', $file, $matches, PREG_SET_ORDER |  PREG_OFFSET_CAPTURE ))
    {
      # nothing found, so return file contents as-is
      return $file;
    }

    $new_file = "";
    $i = 0;
    foreach ($matches as $match)
    {
      # append the plain PHP code up to the include statement 
      $new_file .= substr($file, $i, $match[0][1] - $i);

      # make sure to honor "include once" files
      if ($match[3][0] != "_once" || !isset($included_files[$match[5][0]]))
      {
         # include this file
         $included_files[$match[5][0]] = true;
         $new_file .= ' ?>'.import_file($match[5][0]).'<?php ';
      }

      # update the index pointer to where the next plain chunk starts
      $i = $match[0][1] + strlen($match[0][0]);
    }

    # append the remainder of the source PHP code
    $new_file .= substr($file, $i);

    return str_replace('?><?php', '', $new_file);
  }
?>

上記のコードには多くの警告があり、そのうちのいくつかは回避できます。(私はそれを他の誰かのための演習として残しておきます。) いくつか例を挙げると:

  • ブロックを尊重しないため<?php ?>、HTML 内で一致します。
  • PHP のルールを認識しないため、PHP コメント内で一致します。
  • 変数インクルードを処理できません (例: include $foo;)
  • スコープ エラーが発生する可能性があります。(例: if (true) include('foo.php'); はif (true) { include('foo.php'); }
  • 無限再帰インクルードをチェックしません
  • インクルード パスを認識していない
  • 等...

しかし、そのような原始的な状態でも、まだ役に立つかもしれません。

于 2010-02-14T01:35:28.527 に答える
0

get_included_filesご想像のとおり、含まれているすべてのファイルの配列を返す組み込み関数を使用できます。

以下に例を示します。このコードを mainfile.php の END にドロップしてから、mainfile.php を実行します。

  $includes = get_included_files();

  $all = "";
  foreach($includes as $filename) {
    $all .= file_get_contents($filename);
  }
  file_put_contents('all.php',$all);

注意すべき点がいくつかあります。

  • 実際に処理されないインクルード (つまり、関数内のインクルード) は、最終ファイルにダンプされません。実際に実行されたもののみが含まれます。
  • これにも各ファイルの周りがありますが、単一のテキスト ファイル内に問題なく、そのような複数のブロックを含めることができます。
  • これには、別のインクルード内に含まれるものがすべて含まれます。
  • はい、get_included_files実際に実行されているスクリプトも一覧表示されます。

このツールをドロップインではなくスタンドアロン ツールにする必要がある場合は、初期ファイルを読み込んで、このコードをテキストとして追加し、全体を評価することができます (危険な可能性があります)。

于 2010-02-13T14:56:19.300 に答える