BenMorel
BenMorel

Reputation: 36554

How to tell if a class is an internal class or a user class?

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

Answers (7)

Christian Kiewiet
Christian Kiewiet

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

MarcDefiant
MarcDefiant

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

Otar
Otar

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

Andrius Naruševičius
Andrius Naruševičius

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

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

h2ooooooo
h2ooooooo

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

Prisoner
Prisoner

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

Related Questions