سؤال

أتساءل ما هي أفضل الممارسات للتعامل مع مشكلة الاضطرار إلى "تضمين" العديد من الملفات في برامج PHP النصية الخاصة بي للتأكد من أن جميع الفئات التي أحتاج إلى استخدامها يمكن الوصول إليها من خلال البرنامج النصي الخاص بي.

حاليا، أنا فقط باستخدام include_once لتضمين الفئات التي يمكنني الوصول إليها مباشرة.كل واحد من هؤلاء سوف include_once الفئات التي يصلون إليها.

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

هل هناك طريقة أسهل للتعامل مع هذا؟

أم أن PHP غير مناسب لـ "مؤسسة"اكتب التطبيقات التي تحتوي على الكثير من الكائنات المختلفة الموجودة جميعها في ملفات منفصلة يمكن أن تكون في العديد من الأدلة المختلفة.

هل كانت مفيدة؟

المحلول

أنا تطبيقاتي عادة ما يكون لدي setup.php ملف يتضمن جميع الفئات الأساسية (أي.الإطار والمكتبات المصاحبة).يتم تحميل فئاتي المخصصة باستخدام أداة التحميل التلقائي بمساعدة خريطة تخطيط الدليل.

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

autobuild.php

define('MAP', 'var/cache/autoload.map');
error_reporting(E_ALL);
require 'setup.php';
print(buildAutoloaderMap() . " classes mapped\n");

function buildAutoloaderMap() {
    $dirs = array('lib', 'view', 'model');
    $cache = array();
    $n = 0;
    foreach ($dirs as $dir) {
        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $entry) {
            $fn = $entry->getFilename();
            if (!preg_match('/\.class\.php$/', $fn))
                continue;
            $c = str_replace('.class.php', '', $fn);
            if (!class_exists($c)) {
                $cache[$c] = ($pn = $entry->getPathname());
                ++$n;
            }
        }
    }
    ksort($cache);
    file_put_contents(MAP, serialize($cache));
    return $n;
}

تحميل تلقائي.php

define('MAP', 'var/cache/autoload.map');

function __autoload($className) {
    static $map;
    $map or ($map = unserialize(file_get_contents(MAP)));
    $fn = array_key_exists($className, $map) ? $map[$className] : null;
    if ($fn and file_exists($fn)) {
        include $fn;
        unset($map[$className]);
    }
}

لاحظ أن اصطلاح تسمية الملف يجب أن يكون [class_name].class.php.سيتم تغيير فئات الدلائل autobuild.php.يمكنك أيضًا تشغيل أداة الإنشاء التلقائي من وظيفة التحميل التلقائي في حالة عدم العثور على الفئة، لكن ذلك قد يؤدي إلى دخول برنامجك في حلقة لا نهائية.

المصفوفات المتسلسلة سريعة الرتق.

@ جيسون مايكل:PHP 4 ميت.تخلص منه.

نصائح أخرى

يمكنك تحديد وظائف التحميل التلقائي المتعددة باستخدام spl_autoload_register:

spl_autoload_register('load_controllers');
spl_autoload_register('load_models');

function load_models($class){
    if( !file_exists("models/$class.php") )
        return false;

    include "models/$class.php";
    return true;
}
function load_controllers($class){
    if( !file_exists("controllers/$class.php") )
        return false;

    include "controllers/$class.php";
    return true;
}

يمكنك أيضًا تحديد موقع ملف الفئة برمجيًا باستخدام اصطلاحات التسمية المنظمة التي يتم تعيينها إلى الدلائل الفعلية.هذه هي الطريقة التي يفعلها Zend إطار زند.لذلك عندما تتصل Zend_Loader::loadClass("Zend_Db_Table"); يقوم بتقسيم اسم الفئة إلى مجموعة من الدلائل عن طريق التقسيم على الشرطة السفلية، ثم تنتقل فئة Zend_Loader لتحميل الملف المطلوب.

كما هو الحال مع جميع وحدات Zend، أتوقع أنه يمكنك استخدام المُحمل بمفرده مع الفئات الخاصة بك ولكني استخدمته فقط كجزء من موقع يستخدم Zend's MVC.

ولكن كانت هناك مخاوف بشأن الأداء تحت التحميل عند استخدام أي نوع من التحميل الديناميكي للفئة، على سبيل المثال انظر هذا بلوق وظيفة مقارنة Zend_Loader بالتحميل الصعب لملفات الفئة.

بالإضافة إلى عقوبة الأداء المتمثلة في الاضطرار إلى البحث في مسار تضمين PHP، فإنه يهزم التخزين المؤقت لشفرة التشغيل.من تعليق على هذا المنشور:

عند استخدام أي أداة تحميل من الفئة الديناميكية، لا تستطيع APC تخزين هذه الملفات مؤقتًا بشكل كامل لأنها غير متأكدة من الملفات التي سيتم تحميلها بناءً على أي طلب واحد.من خلال التحميل الصعب للملفات، يمكن لـ APC تخزينها مؤقتًا بالكامل.

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

وبدلاً من ذلك، احتفظ بمصفوفة ترابطية من الأسماء لحفظ مواقع الفصل الدراسي الخاص بك والسماح لها بذلك __autoload الاستعلام عن هذه المصفوفة.

من بين الاقتراحات المقدمة حتى الآن، أنا متحيز لاقتراح كيفن، لكن ليس من الضروري أن تكون مطلقة.أرى خيارين مختلفين لاستخدامهما مع __autoload.

  1. ضع كافة ملفات الفصل في دليل واحد.قم بتسمية الملف بعد الفصل، على سبيل المثال، classes/User.php أو classes/User.class.php.
  2. فكرة كيفن هي وضع النماذج في دليل واحد، ووحدات التحكم في دليل آخر، وما إلى ذلك.يعمل بشكل جيد إذا كانت جميع فصولك تتناسب بشكل جيد مع إطار عمل MVC، ولكن في بعض الأحيان، تصبح الأمور فوضوية.
  3. قم بتضمين الدليل في اسم الفصل.على سبيل المثال، فئة تسمى Model_User يمكن أن تكون موجودة بالفعل في classes/Model/User.php.ستعرف وظيفة __autoload الخاصة بك كيفية ترجمة الشرطة السفلية إلى فاصل دليل للعثور على الملف.
  4. ما عليك سوى تحليل بنية الدليل بالكامل مرة واحدة.إما في وظيفة __autoload، أو حتى في نفس ملف PHP الذي تم تعريفه فيه، قم بالتكرار فوق محتويات الملف classes الدليل وذاكرة التخزين المؤقت ما هي الملفات الموجودة فيها.لذلك، إذا حاولت تحميل User الصف، لا يهم إذا كان في classes/User.php أو classes/Models/User.php أو classes/Utility/User.php.بمجرد العثور عليه User.php في مكان ما في classes الدليل، فإنه سيعرف الملف الذي سيتم تضمينه عند User يحتاج الفصل إلى التحميل التلقائي.

@كيفن:

كنت أحاول فقط الإشارة إلى أن spl_autoload_register هو بديل أفضل لـ __autoload حيث يمكنك تحديد أدوات تحميل متعددة، ولن تتعارض مع بعضها البعض.مفيد إذا كان عليك تضمين المكتبات التي تحدد وظيفة __autoload أيضًا.

هل أنت متأكد؟ال توثيق يقول بشكل مختلف:

إذا كان الكود الخاص بك يحتوي على وظيفة __autoload موجودة، فيجب تسجيل هذه الوظيفة بشكل صريح في مكدس __autoload.وذلك لأن spl_autoload_register() سيستبدل بشكل فعال ذاكرة التخزين المؤقت للمحرك لوظيفة __autoload إما بواسطة spl_autoload() أو spl_autoload_call().

=> يجب عليك تسجيل أي مكتبة بشكل صريح __autoload أيضًا.ولكن بصرف النظر عن ذلك، فأنت بالطبع على حق، فهذه الوظيفة هي البديل الأفضل.

__autoload سوف تعمل، ولكن فقط في PHP 5.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top