Reputation: 36554
Is there a way in PHP to tell (programmatically, obviously) if a given class is an internal class (such as DateTime
) or a user class (class MyClass
)?
In case you wonder (and I'm sure you do), this is because ReflectionClass::newInstanceWithoutConstructor() throws an exception when used on internal classes, and as I'm writing a library to deep-copy objects, it must skip these internal classes.
Yes, I could just catch the ReflectionException
, but this exception is thrown for other reasons as well (such as a non-existing class), and is not thrown for all system classes. so it's not exactly fulfilling my needs.
Upvotes: 13
Views: 966
Reputation: 880
Food for thought, based on Дамян Станчев's suggestion:
You could just run a PHP interpreter via shell_exec()
that will spew out get_declared_classes()
. Capture the output of that, and you should have a "clean" list of system classes.
Extending Mogria's answer, this one should work just fine (don't give me credit for this though, as it was Mogria's answer that got it right ;-)):
function getUserDefinedClasses() {
return array_filter(get_declared_classes(),
function ($class) {
$reflectionClass = new ReflectionClass($class);
return $reflectionClass->isUserDefined();
});
}
Upvotes: 2
Reputation: 6889
A cleaner solution than using shell_exec
whould be to use reflection:
$reflection = new ReflectionClass('SomeClass');
if($reflection->isUserDefined()) {
// 'SomeClass' is not an PHP internal
}
Instead of an string ('SomeClass'
) you can also pass an object. For more information lookup Reflection and
ReflectionClass::isUserDefined()
in the PHP Manual
Upvotes: 15
Reputation: 2591
What about storing calling get_declared_classes() data before any autoloading/include/require is made and later checking class name in this storage?
Upvotes: 0
Reputation: 8578
This example prints out all the classes with your classes seeming to be at the end of the list. Maybe this can help.
Upvotes: 0
Reputation: 2664
Can't you use get_declared_classes()
in the beginning of your script, store the data in an array and then do an array_diff()
with the stored data and the response from get_declared_classes()
and check if the class you're checking is in the difference using in_array()
?
Upvotes: 0
Reputation: 39540
You should be able to imitate the reflection behaviour by extending the class you're trying to copy, and overriding the __construct
function:
<?php
class MyClass extends ExtendingClass {
public function __construct() {
/* Override default constructor */
}
}
?>
Which could essentially be made dynamic by using 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");
?>
HOWEVER: Using eval
can be useful in this case, but also reveals a rather large security-hole if anything user submitted can be submitted in any way to change the contents of $class
. If you understand these limitations, and security implications, you should be able to use this.
Upvotes: 0
Reputation: 27628
Interesting question, one way I can think is by checking the namespace, for example all of your classes would be defined under namespace MyApp
and then check:
if(class_exists('\\DateTime')){
continue;
}
Kind of ugly, I know.
Upvotes: 3