دراجة أخرى: كتابة برنامج التحميل التلقائي الخاص بك لفئة Bitrix

بغض النظر عما يقوله أي شخص ، ولكن أعتقد أن اختراع الدراجة هو شيء مفيد. بالطبع ، يعد استخدام المكتبات والأطر الجاهزة الجاهزة أمرًا جيدًا ، ولكن في بعض الأحيان يجب عليك تأجيلها وإنشاء شيء خاص بك. هكذا نحافظ على الدماغ في حالة جيدة ونحقق إمكاناتنا الإبداعية.



سوف تكون المقالة طويلة ، لذا استرخ عندما أبدأ.





UPD: كما اتضح ، فإن الطريقة الموضحة في هذه المقالة لا تساعد في جميع الحالات - عندما يتعلق الأمر بـ ORM ، حيث تختلف تسمية الفئات والملفات (على سبيل المثال ، فئة ConfigTable ، الموجودة في ملف config.php) ، تبدأ المشاكل والأخطاء. لذلك ، لا يزال من الأفضل استخدام Composer.




إذن ، Bitrix ، أو بالأحرى ، Bitrix Framework. على الرغم من وجود واجهة برمجة تطبيقات غنية ، هناك حاجة من وقت لآخر لإنشاء فصولك / مكتباتك الخاصة ، بالإضافة إلى ربط تلك التابعة لجهات خارجية. لذلك ، بادئ ذي بدء ، دعنا نلقي نظرة على طرق التحميل التلقائي الحالية.



حسن العمر يشمل / يتطلب. أضفته فقط كمرجع تاريخي. على الرغم من فجر مسار البرمجة الخاص بي ، قمت بوضع الفئات والمكتبات اللازمة في مجلد منفصل ، وأنشأت ملفًا منفصلاً حيث قمت بتضمين كل هذه الفئات ثم أدرجت الملف مع شوائب (أعتذر عن الحشو).



ملحن.يتيح لك ربط كل من الفصول الدراسية ومكتبات الطرف الثالث. ومع ذلك ، عند إضافة فئات جديدة ، فإنه يتطلب تحديثًا يدويًا. بالإضافة إلى ذلك ، يجب أيضًا كتابة الفئات والملفات ومساحات الأسماء يدويًا. يمكنك أن تقرأ عن كيفية تكوين صداقات 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)


لذلك ، يبقى علينا تنفيذ طريقة التحميل التلقائي للصفيف الناتج. لهذا الغرض ، سنكتب أسلوبًا يحمل أكثر الأسماء العادية شيوعًا ، حيث سنمرر المصفوفة الناتجة:




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


تستخدم هذه الطريقة محمل بتريكس ، الذي يسجل مصفوفة مع فئاتنا.



الآن لم يتبق سوى القليل جدًا - لتشكيل مصفوفة مع الفئات وتحميلها باستخدام الفصل الدراسي الذي كتبناه. للقيام بذلك ، في مجلد 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;
}


بدلا من الاستنتاج



حسنًا ، تهانينا ، دراجتنا جاهزة وتقوم بعمل ممتاز بوظيفتها.

المصادر ، كما هو الحال دائمًا ، على جيثب .



شكرا على انتباهك.



All Articles