Включение дочернего класса требует, чтобы родительский класс был включен первым - PullRequest
0 голосов
/ 18 января 2012

Я уже задавал вопрос, похожий на этот, но я думаю, что он был плохо сформулирован и запутан, так что, надеюсь, я смогу сделать его немного понятнее.

Я программирую в родной файловой системе Linux.

У меня есть класс HelpTopic:

class HelpTopic extends Help{}

И класс Help:

class Help{}

Теперь я включаю HelpTopic:

include('HelpTopic.php');

И хотя я не создаю экземпляр HelpTopic с new HelpTopic() PHP (в файловой системе Linux) все еще читает сигнатуру класса и пытается загрузить справку с HelpTopic.

Я не получаю такое поведение из файла cifsОбщая система из системы Windows.

Мое предположение заключается в том, что в Linux есть некоторая странность, которая заставляет PHP реагировать таким образом, но не знаю, что именно.

У кого-нибудь есть какие-либо идеи или решения дляэта проблема?

РЕДАКТИРОВАТЬ:

Я добавил свою функцию загрузки, чтобы показать, что я делаю:

public static function import($cName, $cPath = null){

    if(substr($cName, -2) == "/*"){

        $d_name = ROOT.'/'.substr($cName, 0, -2);
        $d_files = getDirectoryFileList($d_name, array("\.php")); // Currently only accepts .php

        foreach($d_files as $file){
            glue::import(substr($file, 0, strrpos($file, '.')), substr($cName, 0, -2).'/'.$file);
        }
    }else{
        if(!$cPath) $cPath = self::$_classMapper[$cName];

        if(!isset(self::$_classLoaded[$cName])){
            self::$_classLoaded[$cName] = true;
            if($cPath[0] == "/" || preg_match("/^application/i", $cPath) > 0 || preg_match("/^glue/i", $cPath) > 0){
                return include ROOT.'/'.$cPath;
            }else{
                return include $cPath;
            }
        }
        return true;
    }
}

Я вызываю это, делая glue::inmport('application/models/*');, и это идетвключая все модели в моем приложении.Дело в том, что PHP в файловой системе на основе Linux (не в cifs) пытается загрузить родителей моих классов без создания экземпляров.

Это довольно базовая функция, которая существует в большинстве сред (на самом деле большая часть этого кода)основан на версии yiis), поэтому я запутался, почему другие не столкнулись с этой проблемой.

1 Ответ

4 голосов
/ 18 января 2012

И хотя я не создаю экземпляр HelpTopic с new HelpTopic() PHP по-прежнему читает сигнатуру класса и пытается загрузить справку с HelpTopic.

Исправить.

ВЧтобы знать, как правильно определить класс, PHP должен разрешить любые родительские классы (все пути вверх) и любые интерфейсы.Это делается, когда класс определен, а не когда он используется.

Вероятно, вам следует просмотреть документацию PHP по наследованию , которая включает примечание, объясняющее это поведение:

Если не используется автозагрузка, классы должны быть определены до их использования.Если класс расширяет другой, тогда родительский класс должен быть объявлен перед структурой дочернего класса.Это правило применяется к классу, который наследует другие классы и интерфейсы.

Существует два способа решения этой проблемы.

Сначала добавьте require_once вверху файла, которыйопределяет дочерний класс, который включает файл, определяющий родительский класс.Это самый простой и простой способ, если у вас нет автозагрузчика.

Второй способ - определить автозагрузчик.Это также описано в документации .


... вещь ... которую вы используете, есть не автозагрузчик.На самом деле, это ужасная мерзость, которую вы должны очистить от своего кода.Это снижение производительности, и вы не должны его использовать.Это также случается с ошибкой.

У нас здесь нет определения getDirectoryFileList(), поэтому я предполагаю, что оно использует либо glob(), либо DirectoryIterator.Это источник вашей проблемы.Вы получаете список файлов в порядке undefined .Или, скорее, в любом порядке, который базовая файловая система хочет дать вам.На одной машине файловая система, вероятно, дает Help.php до HelpTopic.php, а на другой машине HelpTopic.php замечено first .

AtНа первый взгляд, вы можете подумать, что это можно исправить с помощью простого sort, но это не так.Что произойдет, если вы создадите класс Zebra, а затем вам потребуется создать AlbinoZebra, который наследуется от него?Никакая сортировка каталогов не удовлетворит требования как «загрузить ASCIIbetical», так и «мне нужна Zebra, чтобы быть первой».

Давайте также коснемся проблемы производительности, связанной с производительностью.На каждый запрос , вы открываете каталог и читаете список файлов.Это чертовски много stat звонков.Это медленно.Очень медленно.Затем, один за другим, , независимо от того, понадобятся они вам или нет , вы включаете файлы.Это означает, что PHP должен компилировать и интерпретировать каждый из них.Если вы не используете кэш байт-кода, это приведет к полному снижению производительности, если количество файлов в нем увеличится до нетривиального числа.

Правильно созданный автозагрузчик полностью решит эту проблему.Автозагрузчики запускают по требованию , что означает, что они никогда не будут пытаться включить файл до того, как он действительно понадобится.Хорошо работающие автозагрузчики будут знать, где находится файл класса, основываясь только на одном имени.В современном PHP принято называть ваши классы так, чтобы они были легко найдены автозагрузчиком с использованием пространств имен или подчеркиваний - или обоих - для сопоставления разделителей каталогов.(Значение namespace \Models; class Help или class Models_Help будет жить в Models/Help.php)

К сожалению, большинство примеров здесь не пригодятся, так как я не знаю, какие странные вещи делает ваша пользовательская среда.Взгляните на автозагрузчик Zend Framework , который использует регистрацию префиксов для указания префиксов классов (Model_) на каталоги.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...