13

PHP 中有没有办法告诉(显然是通过编程方式)给定的类是内部类(例如DateTime)还是用户类class MyClass)?

如果您想知道(我相信您会知道),这是因为ReflectionClass::newInstanceWithoutConstructor()在内部类上使用时会引发异常,并且当我正在编写一个库来深度复制对象时,它必须跳过这些内部类。

是的,我可以只捕获ReflectionException,但是由于其他原因(例如不存在的类)也会引发此异常,并且不会针对所有系统类引发此异常。所以它并不能完全满足我的需求。

4

7 回答 7

15

比使用更清洁的解决方案shell_exec应该是使用反射

$reflection = new ReflectionClass('SomeClass'); 
if($reflection->isUserDefined()) {
   // 'SomeClass' is not an PHP internal
}

除了字符串 ( 'SomeClass'),您还可以传递一个对象。有关更多信息,请查阅反射ReflectionClass::isUserDefined()PHP 手册

于 2013-06-06T12:11:51.837 回答
3

有趣的问题,我能想到的一种方法是检查命名空间,例如,您的所有类都将在下面定义namespace MyApp,然后检查:

if(class_exists('\\DateTime')){
    continue;
}

有点丑,我知道。

于 2013-06-06T11:45:03.807 回答
2

深思熟虑,基于 Дамян Станчев 的建议:

你可以通过shell_exec()它来运行一个 PHP 解释器get_declared_classes()。捕获它的输出,你应该有一个“干净”的系统类列表。


扩展 Mogria 的答案,这个应该可以正常工作(尽管不要相信我,因为 Mogria 的答案是正确的;-)):

function getUserDefinedClasses() {
    return array_filter(get_declared_classes(),
                        function ($class) {
                           $reflectionClass = new ReflectionClass($class);
                           return $reflectionClass->isUserDefined();
                         });
}
于 2013-06-06T11:59:09.633 回答
0

这个例子打印出所有的类,你的类似乎在列表的末尾。也许这会有所帮助。

于 2013-06-06T11:51:38.857 回答
0

您应该能够通过扩展您尝试复制的类并覆盖该__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. 如果您了解这些限制和安全隐患,您应该能够使用它。

于 2013-06-06T11:48:11.003 回答
0

在进行任何自动加载/包含/要求之前存储调用 get_declared_classes()数据并稍后检查此存储中的类名怎么样?

于 2013-06-06T11:57:21.620 回答
0

您不能get_declared_classes()在脚本的开头使用,将数据存储在一个数组中,然后array_diff()对存储的数据和响应进行操作,get_declared_classes()并检查您正在检查的类是否与使用不同in_array()

于 2013-06-06T11:50:12.560 回答