Reputation: 215
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
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
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
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