Автозагрузка Composer не загружает базовый класс в родительскую папку

но композитор автоматически загружает один и тот же базовый класс в той же папке.

Моя ошибка: Неустранимая ошибка: класс 'VendorName\ParentFolder\Enums\BasicEnum не найден в C:\VendorName\www\src\ParentFolder\Enums\MyEnumeration.php в строке 5.

MyEnumeration.php:

<?php
  namespace VendorName\ParentFolder\Enums;


  abstract class MyEnumeration extends BasicEnum {
      const ConstantOne = 1;
      const ConstantTwo = 2;
      const ConstantThree = 3;
}

и BasicEnum.php:

<?php
namespace VendorName\ParentFolder;

abstract class BasicEnum {
    private static $constCacheArray = NULL;

    private function __construct() { }

    private static function getConstants() {
        if (self::$constCacheArray == NULL) {
            self::$constCacheArray = [];
        }
        $calledClass = get_called_class();
        if (!array_key_exists($calledClass, self::$constCacheArray)) {
            $reflect = new ReflectionClass($calledClass);
            self::$constCacheArray[$calledClass] = $reflect->getConstants();
        }
        return self::$constCacheArray[$calledClass];
    }

    public static function isValidName($name, $strict = false) {
        $constants = self::getConstants();

        if ($strict) {
            return array_key_exists($name, $constants);
        }

        $keys = array_map('strtolower', array_keys($constants));
        return in_array(strtolower($name), $keys);
    }

    public static function isValidValue($value, $strict = true) {
        $values = array_values(self::getConstants());
        return in_array($value, $values, $strict);
    }
}

Моя структура папок:

+ VendorName
  + www
    + src
      + ParentFolder
        + Enums
              MyEnumeration.php
          BasicEnum2.php

И автозагрузка построена через:

composer dump-autoload

с композитором.json:

{
    "autoload": {
        "psr-4": { "VendorName\\": "src/"}

    }
}

Моя .php-страница:

<h1>Composer Autoload Test</h1>
<p>Trying to load a class where base class is in parent folder.
<p>(Using the PHP.net BasicEnum example).
<br/>
<?php
    require __DIR__ . '/vendor/autoload.php';

    use VendorName\ParentFolder;
    use VendorName\ParentFolder\Enums;



    echo '<br/><br/>';
    if (class_exists('MyEnumeration')) {
        echo 'MyEnumeration exists';
    }
    else {
        echo 'MyEnumeration does NOT exist';   // This line prints out in browser.
    }
    echo '<br/><br/>';

    echo '<br/><br/>';
    if (class_exists('VendorName\ParentFolder\Enums\MyEnumeration')) {  // This line blows up because BaseEnum is not found in MyEnumeration.php.
        echo 'VendorName\ParentFolder\Enums\MyEnumeration exists';
    }
    else {
        echo 'VendorName\ParentFolder\Enums\MyEnumeration does NOT exist';
    }
    echo '<br/><br/>';


    echo '<br/><br/>';
    if (defined('VendorName\ParentFolder\Enums\MyEnumeration::ConstantOne')) {
        echo 'VendorName\ParentFolder\Enums\MyEnumeration::ConstantOne exists';
    }
    else {
        echo 'VendorName\ParentFolder\Enums\MyEnumeration::ConstantOne does NOT exist';
    }
    echo '<br/><br/>';  


    echo 'NotExist:' . (MyEnumeration::isValidName('NotExist') ? 'true' : 'false') . '<br/>';
    echo 'ConstantOne:' . (MyEnumeration::isValidName('ConstantOne') ? 'true' : 'false') . '<br/>';
    echo 'ConstantTwo:' . (MyEnumeration::isValidName('ConstantTwo') ? 'true' : 'false') . '<br/>';
    echo 'ConstantThree:' . (MyEnumeration::isValidName('ConstantThree') ? 'true' : 'false') . '<br/>';

?>

Наконец, я должен полностью квалифицировать MyEnumeration с помощью пространства имен, иначе оно не будет найдено, даже если у меня есть оператор «использовать» и использовать автозагрузку композитора.


person Community    schedule 18.09.2017    source источник
comment
Я немного запутался в вашей структуре папок. В каком каталоге находится ваш composer.json?   -  person Matt Gibson    schedule 19.09.2017
comment
(Кроме того, является ли BasicEnum2.php просто опечаткой?)   -  person Matt Gibson    schedule 19.09.2017
comment
composer.json находится в той же папке, что и папка «src».   -  person    schedule 19.09.2017
comment
Да, BasicEnum2.php — опечатка.   -  person    schedule 19.09.2017


Ответы (2)


Ваш класс MyEnumeration находится в пространстве имен VendorName\ParentFolder\Enums. Следовательно, он не может найти BasicEnum в качестве символа, поскольку он находится в пространстве имен выше, \VendorName\ParentFolder. Вы можете указать это абсолютно в своем дочернем классе:

abstract class MyEnumeration extends \VendorName\ParentFolder\BasicEnum {

Вам также потребуется указать глобальное пространство имен для ReflectionClass в вашем BasicEnum:

$reflect = new \ReflectionClass($calledClass);

Также обратите внимание, что вы не можете просто импортировать все из пространства имен используя use. Вам нужно use определенные классы. Например, на вашей странице php укажите:

use VendorName\ParentFolder\Enums\MyEnumeration;

...чтобы разрешить использование MyEnumeration без квалификатора.

person Matt Gibson    schedule 18.09.2017
comment
ах, СЕЙЧАС документация по инструкции «использовать» имеет смысл, где последний токен является псевдонимом. Это -имя класса. Я думал о последнем подпространстве имен. Это должно быть связано с тем, почему для class_exists требуется полное имя класса? Если да, то мне не хватает автозагрузчика. Я думал, что он сказал, что загрузит имя класса в любом месте под src без полного имени. - person ; 19.09.2017
comment
› $reflect = новый \ReflectionClass($ CalledClass); - не уверен, куда это идет. Этот BasicEnum взят из документа PHP.Net. - person ; 19.09.2017
comment
В классе BasicEnum есть строка кода, в которой используется ReflectionClass без квалификатора области видимости, т. е. $reflect = new ReflectionClass($calledClass); (обратите внимание на отсутствие обратной косой черты). Я предполагаю, что код, полученный с php.net, еще не находился в пространстве имен. ? Поскольку вы поместили этот код в пространство имен, вам понадобится обратная косая черта, чтобы вернуться к глобальной области видимости и найти ReflectionClass. В противном случае он будет пытаться найти \VendorName\ParentFolder\ReflectionClass, которого не существует. - person Matt Gibson; 19.09.2017
comment
Я получил этот код BasicEnum здесь: secure.php.net/manual/en/class .splenum.php - person ; 19.09.2017
comment
Это исправляет мою опубликованную ошибку. Я думаю, что ТАК — это один сбой/исправление на пост, верно? Надеюсь, я не испытываю удачу, чтобы спросить, почему последние четыре строки с isValidName не могут найти MyEnumeration (класс 'MyEnumeration' не найден...): - person ; 19.09.2017
comment
Ага; как я уже сказал, он не находится в пространстве имен, поэтому он прекрасно видит ReflectionClass. Код и ReflectionClass находятся в глобальном пространстве имен. Теперь, когда вы поместили его в пространство имен VendorName\ParentFolder, вам нужно будет сказать \ReflectionClass вместо ReflectionClass, чтобы выйти из вашего пространства имен и найти его. - person Matt Gibson; 19.09.2017
comment
И я знаю, почему последние четыре строки не работают, по той же причине, что и другое «использование». Это отвечает на мой вопрос. - person ; 19.09.2017
comment
Для глобального пространства имен, помня, что чтение / было глобальным пространством имен. Не понимал, что мне нужно, чтобы он исходил непосредственно от PHP.net. - person ; 19.09.2017
comment
@ PHPDev75 Имейте в виду, что все, что находится под заголовком «Примечания пользователя» на страницах PHP.net, фактически является комментариями к руководству и может быть добавлено кем угодно. Часто есть фрагменты и сниппеты, над которыми нужно поработать, чтобы они были полностью полезными. - person Matt Gibson; 19.09.2017

Похоже, у вас есть
файл src\ParentFolder\Enums\BasicEnum2.php
с классом BasicEnum в пространстве имен VendorName\ParentFolder

но у вас должен быть файл src\ParentFolder\Enums\BasicEnum.php (без 2)
и в вашем сценарии MyEnumeration.php у вас должен быть этот блок использования:

use VendorName\ParentFolder\BasicEnum;
person cn007b    schedule 18.09.2017
comment
Это тип O, это BasicEnum.php. то есть имя класса = имя файла, тот же случай (согласно PSR-4, в котором я новичок). - person ; 19.09.2017
comment
У вас есть use VendorName\ParentFolder\BasicEnum; в MyEnumeration.php? - person cn007b; 19.09.2017
comment
Я этого не сделал, но Мэтт Гибсон ответил мне первым. :-( Последний токен в 'use' - это имя класса, а не подпространство имен класса. Нужно еще раз перечитать документацию по пространству имен (и очистить голову от того, как это работает на других языках ;-) Кажется, 'use' должно быть сокращение для ЛЮБОГО класса в этом пространстве имен. Теперь я запутался в автозагрузке, говоря, что любой класс загружен. Какой смысл, если мне нужно «использовать» каждый отдельный класс? - person ; 19.09.2017
comment
@ PHPDev75 Пространства имен и автозагрузчик здесь действительно связаны только соглашением. Автозагрузчик избавляет вас от необходимости вручную include файлов в PHP (и упрощает повторное использование кода в таких системах, как Composer). Пространства имен предназначены для разделения кода, чтобы, если вы написали класс BasicEnum, он не конфликтовал с чьим-то еще классом BasicEnum, поскольку вы поместите их в свое конкретное пространство имен. Отношение автозагрузки к пространству имен в PSR-4 на самом деле просто хитрый хак, чтобы упростить написание класса автозагрузчика, который может быстро находить произвольные классы. - person Matt Gibson; 19.09.2017
comment
@MattGibson Итак, если у меня есть одиннадцать классов для подростков в MyNamespace1, мне придется «использовать» все одиннадцать подростков? Я думаю, я мог бы написать свой собственный автозагрузчик, чтобы сделать это для меня, но я думаю, что наверняка кто-то уже сделал это, так как это работает на других языках - включая только пространство имен, каждый класс в этом пространстве имен разрешим. - person ; 19.09.2017
comment
Если вы хотите ссылаться на них, не вводя каждый раз пространство имен, да. На практике это не кажется слишком трудоемким; Я думаю, возможно, в PHP вы не слишком часто выходите из своего собственного пространства имен в одном файле. (Или, может быть, это просто потому, что я использую такие редакторы, как Eclipse, которые могут use автоматически или выполнять автозаполнение классов в пространстве имен...) (Написание собственного автозагрузчика не поможет, поскольку автозагрузчик не может изменить способ работы пространств имен. Вы можете автоматически загружать пока вы не посинеете, и все, что он будет делать, это включать файлы. Он вообще не изменит пространства имен.) - person Matt Gibson; 19.09.2017