PHP: динамический экземпляр с неполными пространствами имен

#php #namespaces

#php #пространства имен

Вопрос:

Я хотел бы создать экземпляр моего класса, выполняющий :

 use somedirhttp as Http;

$S_bodyWriterType  = 'Http\' . strtolower($S_requestBodyPayloadType) . '\RequestBodyWriter';
$this->_O_requestBodyWriter = new $S_bodyWriterType;
  

Он говорит, что класс не существует. Однако ЭТО сработало бы (здесь не задействована строка) :

 $this->_O_requestBodyWriter = new HttpxmlRequestBodyWriter;
  

И это, конечно, тоже сработало бы (пространство имен является полным) :

 $S_bodyWriterType  = 'somedirhttp\' . strtolower($S_requestBodyPayloadType) . '\' . 'RequestBodyWriter';
$this->_O_requestBodyWriter = new $S_bodyWriterType;
  

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

Спасибо за помощь!

Комментарии:

1. «Он говорит, что класс не существует». => Какой класс? Покажите нам сообщение об ошибке. В любом случае, вы сохраняете всего 8 символов (`somedir`). Вы можете установить для него константу (тоже немного чище ;)).

2. Неустранимая ошибка: класс ‘Http xml RequestBodyWriter’ не найден… И хорошо, да, я рассматривал возможность использования константы в качестве обходного пути. Я наткнулся на этот комментарий «При использовании в качестве строки нам нужно полное имя, поскольку мы не знаем, откуда берется параметр». на bugs.php.net/bug.php?id=51126 . Я думаю, это то же самое для динамических экземпляров со строками…

Ответ №1:

Хорошо, вы сами предоставили отчет об ошибке 😉 Но это факт: если вы определяете classname в строке, это не говорит о том, что объект создан в том же контексте.

 namespace y {
  use ab as B;
  $GLOBALS['class'] = 'B\MyClass';
}
namespace z {
  use kl as B;
  $classname = $GLOBALS['class'];
  $a = new $classname;
}
  

Таким образом, вам нужно определить имена классов в строке с полными параметрами. Я предлагаю использовать константы (namespace- / class-)

 use ab as B;
const NAMESPACE_B = '\a\b';
$classname = NAMESPACE_B . '\MyClass';
  

Если класс, который вы хотите создать, находится в пространстве вложенных имен, помните, что псевдоконстанта __NAMESPACE__ существует всегда;

 namespace a;
use ab as B;
$classname = __NAMESPACE__ . '\b\MyClass';
  

Дополнительно в вашем случае я предлагаю создать фабрику

 use somedirhttp as Http;
class RequestBodyWriterFactory {
  public function create($type) {
    $classname = __NAMESPACE__ . "\$type\RequestBodyWriter";
    return new $classname;
  }
}

// somewere else
$this->_O_requestBodyWriter = $this->factory->create(strtolower($S_requestBodyPayloadType));
  

Таким образом, у вас больше контроля над тем, что создается и как это создается.