65437


自習のために、クラスのautoloaderを実装してみようと思い、参考にComposerのautoloadのソースコードを調べています。Composerを生成された`vendor/composer/auload_read.php`の中で以下のコードが記述されていました。

[code]

    call_user_func(\Composer\Autoload\ComposerStaticIniteabfb31ac75b7f62959148f5cfd8b9da::getInitializer($loader));
    
[/code]

このcall_user_func()はどういった用途で使用されているのでしょうか？  
試しにcall_user_func()を外して`ComposerStaticInitxxx::getInitializer($loader)`を直接呼び出すと、autoloadが正常に機能しないようでした。

call_user_func()はコールバック関数を呼び出す機能でしかなく、`CompposerStaticInit::getInitializer()`ただのpublic
なstaticメソッドとして定義されており、何の意味があるのか、なぜ使用しないとautoloadが機能しないのかがわかりません。


CC BY-SA 4.0
2020-04-04T15:10:27.780
65356
2020-04-07T07:12:14.253
17238
question
php composer
Composerがauto_read.php内でcall_user_func()を使用している意味


[call_user_func()](https://www.php.net/manual/ja/function.call-user-func.php)

> 最初の引数で指定したコールバック関数をコールする

ということなので、  
call_user_func()の第一引数にはコールバック関数を第2引数以降はコールバック関数に渡す引数を呼び出します。

[code]

    <?php
    function func($message)
    {
        echo "$message World!\n";
    }
    
    //以下はすべて同じく関数を呼び出しています。
    $func = "func";
    $func("Hello");
    call_user_func($func, "Hello call_user_func");
    eval("{$func}(\"Hello eval\");");
    
[/code]

つまりは`call_user_func(ComposerStaticInitxxx::getInitializer($loader))`は実行したい関数を`ComposerStaticInitxxx::getInitializer($loader)`
から受け取って実行するという役目をしています。`ComposerStaticInitxxx::getInitializer($loader)`を単体で動かしても、帰ってくるのは関数だけなのでその関数が実行されることはないです。

getInitializer側の実装を確認すると[無名関数](https://www.php.net/manual/ja/functions.anonymous.php)をreturnしているようです。

[code]

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInitXXXXXX::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInitXXXXXX::$prefixDirsPsr4;
            $loader->prefixesPsr0 = ComposerStaticInitXXXXXX::$prefixesPsr0;
            $loader->classMap = ComposerStaticInitXXXXXX::$classMap;
    
        }, null, ClassLoader::class);
    }
    
[/code]

ハッシュ化された静的クラスの変数をloaderの変数に渡したいようですね。

autoload_read.phpは関数を使うタイミングの責任を持ちたい。  
autoload_static.phpは関数の実装の責任を持ちたい。

なのでコールバックを用いた実装になっているようです。

またなぜ無名関数をつかうかというと、その通り命名しなくてよいからですね。  
特定の個所から一度しか呼ばれないコールバックであれば、わざわざ命名して管理すると手間なので  
無名関数でやり取りしたりします。

あとは[コールバック/Callable](https://www.php.net/manual/ja/language.types.callable.php)や[Closureクラス](https://www.php.net/manual/ja/class.closure.php)あたりを学ぶとよいと思います。


CC BY-SA 4.0
2020-04-07T07:12:14.253
65437
2020-04-07T07:12:14.253
22665
65356
answer