別のバイク:Bitrix用に独自のクラスオートローダーを作成する

誰に何を言われても、自転車の発明は役に立つものだと思います。もちろん、既成のライブラリーやフレームワークを使用することは良いことですが、時にはそれらを先延ばしにして、独自のものを作成する必要があります。これが私たちが脳を良好な状態に保ち、私たちの創造的な可能性を実現する方法です。



記事は長くなるので、始めましょう。





UPD:判明したように、この記事で説明する方法はすべての場合に役立つわけではありません-クラスとファイルの名前が異なるORM(たとえば、config.phpファイルにあるConfigTableクラス)では、問題とエラーが始まります。したがって、Composerを使用することをお勧めします。




つまり、Bitrix、つまりBitrix Frameworkです。豊富なAPIが存在するにもかかわらず、独自のクラスやライブラリを作成したり、サードパーティのものを接続したりする必要がある場合があります。したがって、まず、既存のオートロードメソッドを見てみましょう。



古き良きインクルード/必要。私はそれを単に歴史的な参照のために追加しました。プログラミングパスの夜明けですが、必要なクラスとライブラリを別のフォルダーに置き、これらのすべてのクラスを含めた別のファイルを作成し、そのファイルだけをインクルードに含めました(トートロジーをお詫びします)。



作曲。独自のクラスとサードパーティのライブラリの両方を接続できます。ただし、新しいクラスを追加する場合は、手動で更新する必要があります。さらに、クラス自体、ファイル、名前空間も手動で作成する必要があります。作曲家とBitrixの友達を作る方法については、こちらの



Bitrixローダーをご覧くださいモジュールの接続とクラスの自動読み込みの両方に使用されます。ただし、必要なクラスを接続する前に、配列を形成する必要があります。ここで、キーはクラスの名前、およびクラスへのパスの値になります。そして、それはすべて次のようになります:



$classes = [
    'Namespace\\Package\\ClassName' => '/path/to/class.php'
];

Loader::registerAutloadClasses(null, $classes);


カスタムモジュール。彼らはこれが最も推奨される方法であると言います-あなたはモジュールを作成し、管理領域にインストールし、それをどこにでも接続してあなたの喜びのためにそれを使用します。シンプルに見えますが、実際には次のようになっています。



  • クラスの作成に加えて、モジュールのインストールと削除の手順も登録する必要があります。いくつかの必須パラメーターとメソッドがあり、それがないとモジュールが機能しない可能性があります(わかりませんが、テストしていません)。
  • クラスはモジュールを接続しないと機能しません
  • クラスを別のモジュールに移動することが常に意味があるとは限りません


それでも、ローカルモジュールを作成し、さらにいくつかのクラスを追加することにした場合、それらを使用するためにモジュールを再インストールする必要はありません。適切な場所で必要なメソッドを呼び出すだけです。



さて、今、実際には、自転車自体...



上記のすべてのメソッドを分析した後、新しいクラスを特定の場所に追加するだけで十分であり、名前空間とファイルパスの配列に新しい要素を追加することなく、それらが自動的に読み込まれるように、何を考えるべきかを考えました。



その結果、特別なモジュールを作成することが決定されました-奇妙に聞こえるかもしれませんが、このアイデアは、必要なディレクトリからすべてのクラスを自動的にロードするinit.phpにいくつかの関数を追加するよりも成功したように思えました。



モジュールのインストール/削除を作成するプロセスは省略します。必要な人は誰でも、ソースを調べて、主な機能に直接移動します。



なぜなら 最初は、フォルダのネストのレベル数は不明であり、メソッドは再帰的である必要があります。クラスをロードするBitrix \ Main \ Loaderクラスも使用します。



すべてのクラスを/ local / php_interface / libディレクトリに置くことにしたとしましょう:



画像



また、クラスを含まないファイルがあり、オートローダーに含めないようにする必要があるため、この点も考慮する必要があります。



じゃ、行こう。



namespace Ramapriya\LoadManager;

use Bitrix\Main\Loader;

class Autoload
{
}


まず、フォルダのすべてのコンテンツを取得する必要があります。これを行うには、scanDirectoryメソッドを作成します。



    public static function scanDirectory(string $dir) : array
    {
        $result = [];
        $scanner = scandir($dir); //   
        foreach ($scanner as $scan) {
            switch ($scan) {
                // 
                case '.': 
                case '..':
                    break;
                default:
//                          
                    $item = $dir . '/' . $scan; 
                    $SplFileInfo = new \SplFileInfo($item);
    
                    if($SplFileInfo->isFile()) {
//    ,        
                        $result[] = $scan; 
                        
                    } elseif ($SplFileInfo->isDir()) {
//    ,                                 
                        $result[$scan] = self::scanDirectory($item, $result[$scan]); 
    
                    }
            }
        }
    
        return $result;
    }


出力は次のようになります:







ご覧のとおり、ファイル構造が順守されているため、オートロード用の配列の作成を開始できます。



/*     $defaultNamespace,        . 
   php-,      
*/
    public static function prepareAutoloadClassesArray(string $directory, string $defaultNamespace, array $excludeFiles) : array
    {
        $result = [];
//   
        $scanner = self::scanDirectory($directory); 
    
        foreach ($scanner as $key => $value) {
    
            $sep = '\\';
            
            switch(gettype($key)) {
                
                case 'string':
//     ,    
                    $SplFileInfo = new \SplFileInfo($directory . '/' . $key);
                    $classNamespace = $defaultNamespace . $sep . $key;
    
                    if($SplFileInfo->isDir()) {
//   ,    ,   ,    ,      
                        $tempResult = self::prepareAutoloadClassesArray($directory . '/' . $key, $classNamespace, $excludeFiles);
                        foreach($tempResult as $class => $file) {
//         
                            $result[$class] = $file; 
                        }
                    }
    
                    break;
    
                case 'integer':
//    - ,        
                    $SplFileInfo = new \SplFileInfo($directory . '/' . $value);
//      (           ,    )
                    $classNamespace = $defaultNamespace . $sep . str_ireplace('.php', '', $SplFileInfo->getBasename()); 

//      php-
                    if(
                        $SplFileInfo->isFile() &&
                        $SplFileInfo->getExtension() === 'php'
                    ) {
 //      ,      
                        foreach($excludeFiles as $excludeFile) {
                            if($SplFileInfo->getBasename() !== $excludeFile) {
//        
                                $result[$classNamespace] = str_ireplace($_SERVER['DOCUMENT_ROOT'], '', $directory . '/' . $value); 
                            }
                        }                        
                        
                    }
    
                    break;
                    
            }
    
        }
    
        return $result;
    }


すべてが正しく行われている場合は、最終的には、bitrixローダーを使用してオートロードするための生成された配列を取得







します。機能を確認するには、次のクラスを含む例外を含むMainException.phpファイルをフォルダーに追加します。



<?php

namespace Ramapriya\Exceptions;

class MainException extends \Exception
{
    public function __construct($message = null, $code = 0, Exception $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }
}


ご覧のとおり、ファイルはクラスの配列に読み込まれています。







次に、新しい例外を呼び出してみましょう。



throw new Ramapriya\Exceptions\MainException('test exception');


その結果、次のようになります。



[Ramapriya\Exceptions\MainException] 
test exception (0)


したがって、結果の配列にオートローディングメソッドを実装する必要があるだけです。この目的のために、最も一般的な名前であるloadClassesを使用してメソッドを記述し、結果の配列を渡します。




    public static function loadClasses(array $classes, $moduleId = null)
    {
        Loader::registerAutoloadClasses($moduleId, $classes);
    }


このメソッドは、クラスに配列を登録するbitrixローダーを使用します。



これで、ほとんど残っていません-クラスで配列を形成し、記述したクラスを使用してそれらをロードします。これを行うには、libフォルダーにinclude.phpファイルを作成します。



<?php

use Bitrix\Main\Loader;
use Bitrix\Main\Application;
use Ramapriya\LoadManager\Autoload;

//    -      ,     
Loader::includeModule('ramapriya.loadmanager');

$defaultNamespace = 'Ramapriya';
$excludeFiles = ['include.php'];

$libDir = Application::getDocumentRoot() . '/local/php_interface/lib';

$autoloadClasses = Autoload::prepareAutoloadClassesArray($libDir, $defaultNamespace, $excludeFiles);

Autoload::loadClasses($autoloadClasses);


次に、このファイルをinit.phpに含めます。



// init.php

$includeFile = $_SERVER['DOCUMENT_ROOT'] . '/local/php_interface/lib/include.php';

if(file_exists($includeFile)) {
    require_once $includeFile;
}


結論の代わりに



おめでとうございます、私たちのバイクは準備ができており、その機能で素晴らしい仕事をしています。

ソースはいつものようにgithubにあります。



ご清聴ありがとうございました。



All Articles