conanDrum
conanDrum

Reputation: 215

PHP: How to catch Fatal error: Cannot declare class [myclassname], because the name is already in use

I am implementing a plugin controller CLASS for client created custom plugins. Since the names of the classes of each plugin could very well end up clashing with other plugins already installed, I want to make sure we don't get fatal errors when a new plugin comes in. I want to report to the user that the new plugin is clashing with an already installed one.

So basically atm I testing with 2 files both containing exactly the same code and am getting:

Fatal error: Cannot declare class [myclassname], because the name is already in use

I have tried catching this with no success using:

try {
    include_once $file; 
} catch (ClosedGeneratorException|DOMException|ErrorException|IntlException|LogicException|BadFunctionCallException|BadMethodCallException|DomainException|InvalidArgumentException|LengthException|OutOfRangeException|PharException|ReflectionException|RuntimeException|OutOfBoundsException|OverflowException|PDOException|RangeException|UnderflowException|UnexpectedValueException|SodiumException $ex) {
    echo "Unable to load file.";
} 

All these I got from Lists of Throwable and Exception tree as of 7.2.0 in https://www.php.net/manual/en/class.exception.php

The manual specifies that:

The thrown object must be an instance of the Exception class or a subclass of Exception. Trying to throw an object that is not will result in a PHP Fatal Error.

Is it possible that this is not an object of instance/suclass of the Exception class? What am I missing?

Upvotes: 1

Views: 1384

Answers (3)

Mama Nunu
Mama Nunu

Reputation: 1

I have solved such problems the same way we do that in C for header files:

if (!class_exists("My_View_Helper_Bootstrapmenu")): ... define class endif;

Opinions about style and stupidity of code or quality of certain frameworks are not welcome here according to stackoverflow rules so I just post this as-is.

Upvotes: 0

conanDrum
conanDrum

Reputation: 215

In the end, to avoid this fatal error I decide to parse the files for the first available class declaration using tokens as follows:

public function getClassInFile($filenpath) {
    $src = $this->uncommentFile($filenpath);
    $class ='';
    if (preg_match('/class[\s\n]+([a-zA-Z0-9_]+)[\s\na-zA-Z0-9_]+\{/', $src, $matches)) {
        $class = $matches[1];
    }
    return $class;
}

public function uncommentFile($filenpath) {
    $fileStr = file_get_contents($filenpath);
    $newStr  = '';

    $commentTokens = array(T_COMMENT);

    if (defined('T_DOC_COMMENT'))
    $commentTokens[] = T_DOC_COMMENT; // PHP 5
    if (defined('T_ML_COMMENT'))
    $commentTokens[] = T_ML_COMMENT;  // PHP 4

    $tokens = token_get_all($fileStr);

    foreach ($tokens as $token) {    
        if (is_array($token)) {
            if (in_array($token[0], $commentTokens))
            continue;

            $token = $token[1];
        }

        $newStr .= $token;
    }

    return $newStr; 
}

In this way, I can check whether the class I am expecting to find is in there, or if the class in there already exists, thus avoiding to include_once altogether in these cases. Problem solved.

Upvotes: 0

iainn
iainn

Reputation: 17434

Short answer: no, you're not missing anything. Declaring a duplicate class name can't be caught in any version of PHP (including 8.0.0 as far as the alpha releases). See https://3v4l.org/2TLA3

For some additional background, PHP does sometimes move errors like these underneath the Throwable hierarchy, so that they can be detected at runtime. PHP 7 added support for catching an attempt to instantiate a missing class, and 7.3 added support for catching an attempt to extend a missing class. See https://3v4l.org/BDnm9 for a brief demo of those.

Upvotes: 1

Related Questions