Как определить, является ли класс внутренним классом или классом пользователя?
Есть ли способ в PHP рассказать (программно, очевидно), если данный класс является внутренним классом (например, DateTime
) или классом пользователя ( class MyClass
)?
Если вы задаетесь вопросом (и я уверен, что вы это делаете), это потому, что ReflectionClass:: newInstanceWithoutConstructor() выдает исключение при использовании на внутренних классах и поскольку я пишу библиотеку для глубоких копий объектов, она должна пропустить эти внутренние классы.
Да, я мог бы просто поймать ReflectionException
, но это исключение вызывается и по другим причинам (например, несуществующий класс) и не выбрано для всех системных классов. так что это точно не соответствует моим потребностям.
Ответы
Ответ 1
Более чистый раствор, чем использование shell_exec
, который должен использовать отражение:
$reflection = new ReflectionClass('SomeClass');
if($reflection->isUserDefined()) {
// 'SomeClass' is not an PHP internal
}
Вместо строки ('SomeClass'
) вы также можете передать объект. Для получения дополнительной информации Reflection и
ReflectionClass::isUserDefined()
в руководстве по PHP
Ответ 2
Интересный вопрос, один из способов, которым я могу думать, - проверить пространство имен, например, все ваши классы будут определены в namespace MyApp
, а затем проверьте:
if(class_exists('\\DateTime')){
continue;
}
Какой-то уродливый, я знаю.
Ответ 3
Пища для размышлений, основанная на Дамян Станчев:
Вы можете просто запустить PHP-интерпретатор через shell_exec()
, который вытолкнет get_declared_classes()
. Захватите вывод этого, и у вас должен быть "чистый" список системных классов.
Расширение ответа Mogria, это должно работать нормально (не приносите мне в этом благодарность, так как это был ответ Mogria, который правильно понял: -)):
function getUserDefinedClasses() {
return array_filter(get_declared_classes(),
function ($class) {
$reflectionClass = new ReflectionClass($class);
return $reflectionClass->isUserDefined();
});
}
Ответ 4
Вы должны быть способны имитировать поведение отражения, расширив класс, который вы пытаетесь скопировать, и переопределите функцию __construct
:
<?php
class MyClass extends ExtendingClass {
public function __construct() {
/* Override default constructor */
}
}
?>
Что по существу можно сделать динамическим, используя eval
:
<?php
function newInstanceWithoutConstructor($class) {
$className = $class . "Extended" . rand(0, 99999999);
while (class_exists($className)) {
$className = $class . "Extended" . rand(0, 99999999);
}
eval("class " . $className . " extends " . $class . " { public function __construct() { } }");
return new $className();
}
$newInstance = newInstanceWithoutConstructor("DateTime");
?>
ОДНАКО: использование eval
может быть полезно в этом случае, но также показывает довольно большое отверстие безопасности, если любой пользователь, представленный пользователем, может каким-либо образом изменить содержимое $class
, Если вы понимаете эти ограничения и последствия для безопасности, вы должны иметь возможность использовать это.
Ответ 5
Не можете ли вы использовать get_declared_classes()
в начале вашего script, сохраните данные в массиве и затем выполните array_diff()
с сохраненными данными и ответом от get_declared_classes()
и проверьте, не класс ли вы 'проверка выполняется в разнице с помощью in_array()
?
Ответ 6
Этот пример выводит все классы с вашими классами, которые, как представляется, находятся в конце списка. Возможно, это может помочь.
Ответ 7
Как насчет сохранения вызова get_declared_classes() данных до выполняется любая автозагрузка/включение/требование, а затем проверка класса имя в этом хранилище?