1

ディレクトリ構造

learner@debian:~$ tree ~/bin
/home/learner/bin
└── php
    ├── Body
    │   ├── Brain.php
    │   └── Cell
    │       └── Neuron.php
    └── main.php

3 directories, 3 files

最初のコード例

~/bin/php/main.php:

<?php
spl_autoload_register(function ($class) {
    $path = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
    echo "----- Autoload $class from $path -----\n";
    include $path;
});

use Body\Brain;
$brain = new Brain();
?>

~/bin/php/Body/Brain.php:

<?php
namespace Body;

use Body\Cell\Neuron;

class Brain
{
    public function __construct()
    {
        $this->brain = new Neuron();
        $this->brain->talk();
    }
}
?>

~/bin/php/Body/Cell/Neuron.php:

<?php
namespace Body\Cell;
class Neuron
{
    public function talk()
    {
        echo "I am Neuron!\n";
    }
}
?>

次の方法でホームディレクトリから main.php を実行でき、正常に動作します。

learner@debian:~$ php ~/bin/php/main.php 
----- Autoload Body\Brain from Body/Brain.php -----
----- Autoload Body\Cell\Neuron from Body/Cell/Neuron.php -----
I am Neuron!

これが機能することに驚いています。$this->brain = new Neuron();で実行 すると失敗すると思い ~/bin/php/Body/Brain.phpます。この行が検出されると、オートローダーは実行を試みますが、内部にinclude 'Body/Cell/Neuron.php'呼び出されるサブディレクトリはありません。Body~/bin/php/Body

2 番目のコード例

includeオートローダーの代わりにステートメントを使用している別のコード例を示して、最初のコード例が失敗すると予想する理由を説明しましょう。

~/bin/php/main.php を次のように変更:

<?php
include 'Body/Brain.php';
use Body\Brain;
$brain = new Brain();
?>

上記のコードからオートローダーが欠落しており、以前にオートローダーによって実行されていたものと同じ include ステートメントが現在使用されていることを確認してください。

~/bin/php/Body/Brain.php を次のように変更:

<?php
namespace Body;

include 'Body/Cell/Neuron.php';

use Body\Cell\Neuron;

class Brain
{
    public function __construct()
    {
        $this->brain = new Neuron();
        $this->brain->talk();
    }
}
?>

ロードする前にオートローダーによって実行されていたこのコードに、同じ include ステートメントが追加されていることに注意してくださいBody\Cell\Neuron

このコードを実行しようとすると失敗します。

learner@debian:~$ php ~/bin/php/main.php 
PHP Warning:  include(Body/Cell/Neuron.php): failed to open stream: No such file or directory in /home/learner/bin/php/Body/Brain.php on line 4
PHP Warning:  include(): Failed opening 'Body/Cell/Neuron.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /home/learner/bin/php/Body/Brain.php on line 4
PHP Fatal error:  Class 'Body\Cell\Neuron' not found in /home/learner/bin/php/Body/Brain.php on line 12

include 'Body/Cell/Neuron.php';での実行中に、 で呼び出され~/bin/php/Body/Brain.phpたサブディレクトリが見つからないため、この失敗は予期され たものです。Body~/bin/php/Body

質問

の代わりに ~/bin/php/Body/Brain.php使用する ように編集することで、2 番目のコード例を簡単に修正できることがわかっています 。ただし、私の質問は、2 番目のコード例が機能しない理由ではなく、最初のコード例が機能する理由についてです。include 'Cell/Neuron.php';include 'Body/Cell/Neuron.php';

  1. PHP インタープリターが2 番目のコード例でinclude 'Body/Cell/Neuron.php' from~/bin/php/Body/Brain.phpを実行できない場合、オートローダーが最初のコード例で同じ PHP ファイルから同じインクルードを実行するにはどうすればよいでしょうか?
  2. それとも私は間違っていますか?最初のコード例 ~/bin/php/main.phpでは、クラスが最初に使用された場所に関係なく、オートローダーは常にincludeステートメントを実行しているのでinclude 'Body/Cell/Neuron.php'はない でしょうか。この場合、公式ドキュメントのどこでそれについて読むことができますか?~/bin/php/main.phpBody~/bin/php
  3. 私たちの理解を要約すると、一般的に、登録されたオートローダー機能がどこから実行されるのか教えていただけますか? 関数が定義されているスクリプトから?関数が登録されているスクリプトから?それとも、新しいクラスが発生するスクリプトからですか?
4

2 に答える 2

0

ここで自分の質問に答えています。いくつかの実験では、登録されたオートローダー関数は、オートローダーとして登録された場所ではなく、新しいクラスがインスタンス化または使用された場所ではなく、定義されたスクリプトのコンテキストで実行されるように見えます。

ただし、これは私の理論を証明しようとする実験にすぎないため、誰かが公式ドキュメントを引用して私の質問に答えることができれば、それを正解としてマークします.

実験のセットアップ

ディレクトリ構造:

learner@debian:~$ tree ~/bin
/home/learner/bin
└── php
    ├── AutoLoader
    │   ├── AutoLoader.php
    │   └── ClassLoader
    │       └── ClassLoader.php
    ├── Body
    │   ├── Brain.php
    │   └── Cell
    │       └── Neuron.php
    └── main.php

5 directories, 5 files

~/bin/php/AutoLoader/ClassLoader/ClassLoader.phpと呼ばれるオートロード機能が含まれていますClassLoader::loadClass

~/bin/php/AutoLoader/AutoLoader.phpを呼び出してオートロード機能を登録しspl_autoload_register('Autoloader\\ClassLoader\\ClassLoader::loadClass');ます。

ソースコード

~/bin/php/AutoLoader/AutoLoader.php:

<?php
namespace AutoLoader;

include 'ClassLoader/ClassLoader.php';

class AutoLoader
{
    static public function registerAutoloader()
    {
        spl_autoload_register(
                'Autoloader\\ClassLoader\\ClassLoader::loadClass');
    }
}
?>

~/bin/php/AutoLoader/ClassLoader/ClassLoader.php:

~/bin/php/Body/Brain.php:

<?php
namespace Body;

use Body\Cell\Neuron;

class Brain
{
    public function __construct()
    {
        $this->brain = new Neuron();
        $this->brain->talk();
    }
}
?>

~/bin/php/Body/Cell/Neuron.php:

<?php
namespace Body\Cell;
class Neuron
{
    public function talk()
    {
        echo "I am Neuron!\n";
    }
}
?>

~/bin/php/main.php:

<?php
include 'AutoLoader/AutoLoader.php';

use AutoLoader\AutoLoader;
use Body\Brain;

AutoLoader::registerAutoloader();
$brain = new Brain();
?>

実験1

上記のコードを実行すると、エラーが発生します。

learner@debian:~$ php ~/bin/php/main.php 
----- Autoload Body\Brain from Body/Brain.php -----
PHP Warning:  include(Body/Brain.php): failed to open stream: No such file or directory in /home/learner/bin/php/AutoLoader/ClassLoader/ClassLoader.php on line 9
PHP Warning:  include(): Failed opening 'Body/Brain.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /home/learner/bin/php/AutoLoader/ClassLoader/ClassLoader.php on line 9
PHP Fatal error:  Class 'Body\Brain' not found in /home/learner/bin/php/main.php on line 8

観察:オートローダはBody/Brain.phpfrom をインクルードできませんでした~/bin/php/Body/Brain.php

実験2

Bodyディレクトリを移動し~/bin/php/AutoLoaderてコードを実行しても、エラーが発生します。

learner@debian:~$ mv ~/bin/php/Body ~/bin/php/AutoLoader
learner@debian:~$ tree ~/bin
/home/learner/bin
└── php
    ├── AutoLoader
    │   ├── AutoLoader.php
    │   ├── Body
    │   │   ├── Brain.php
    │   │   └── Cell
    │   │       └── Neuron.php
    │   └── ClassLoader
    │       └── ClassLoader.php
    └── main.php

5 directories, 5 files
learner@debian:~$ php ~/bin/php/main.php 
----- Autoload Body\Brain from Body/Brain.php -----
PHP Warning:  include(Body/Brain.php): failed to open stream: No such file or directory in /home/learner/bin/php/AutoLoader/ClassLoader/ClassLoader.php on line 9
PHP Warning:  include(): Failed opening 'Body/Brain.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /home/learner/bin/php/AutoLoader/ClassLoader/ClassLoader.php on line 9
PHP Fatal error:  Class 'Body\Brain' not found in /home/learner/bin/php/main.php on line 8

観察:オートローダはBody/Brain.phpfrom をインクルードできませんでした~/bin/php/AutoLoader/Body/Brain.php

実験3

Bodyディレクトリを移動~/bin/php/AutoLoader/ClassLoaderしてコードを実行すると成功します。

learner@debian:~$ mv ~/bin/php/AutoLoader/Body ~/bin/php/AutoLoader/ClassLoader/Body
learner@debian:~$ tree ~/bin
/home/learner/bin
└── php
    ├── AutoLoader
    │   ├── AutoLoader.php
    │   └── ClassLoader
    │       ├── Body
    │       │   ├── Brain.php
    │       │   └── Cell
    │       │       └── Neuron.php
    │       └── ClassLoader.php
    └── main.php

5 directories, 5 files
learner@debian:~$ php ~/bin/php/main.php 
----- Autoload Body\Brain from Body/Brain.php -----
----- Autoload Body\Cell\Neuron from Body/Cell/Neuron.php -----
I am Neuron!

観察:Body/Brain.phpオートローダーにはfromが含まれている可能性があります~/bin/php/AutoLoader/ClassLoader/Body/Brain.php

結論

3 つの実験の結論は、オートローダーが~/bin/php/AutoLoader/ClassLoader/ディレクトリ、つまりオートローダー機能を定義するスクリプトを含むディレクトリに関してファイルをインクルードしていることを示しているようです。

于 2013-10-06T09:09:52.460 に答える