confusing "cannot redeclare class" error (PHP) - php

I have a strange issue. I have a static method that loads classes (load_library). When it loads a particular class, it gives me a "cannot redeclare class" fatal error, but when testing whether the class exists right before using the load_library method to load it, it says the class does not exist. The load_library method works elsewhere without such errors.
If I take the load_library call out, it says it cannot find the class when the class is actually used a few lines later. Stranger still, if I take out my registered class autoload function instead, everything works perfectly, even though this autoload function doesn't even check the directory that the class I'm trying to load is in.
It's a complicated problem involving many files so it is hard to post code, but does this problem smell familiar to anyone out there?
My load_library method:
public static function load_library($name) {
if (!class_exists($name)) {
if (file_exists('application/libraries/' . $name . '.php')) {
include('application/libraries/' . $name . '.php');
} else {
trigger_error('Request made for non-existant library ('.$name.').', E_USER_ERROR);
}
}
}
My call to the load_library method:
lev::load_library('lev_unit_tester/lev_base_test');
My registered autoload method:
public static function autoloader($name) {
if (class_exists($name)) return;
if (file_exists('application/libraries/' . $name . '.php')) {
include('application/libraries/' . $name . '.php');
}
}
The class I am trying to load (this is where the error occurs):
abstract class lev_base_test {
}
The actual error message:
Fatal error: Cannot redeclare class lev_base_test in /some/path/application/libraries/lev_unit_tester/lev_base_test.php on line 5

try this
// Check to see whether the include declared the class
if (!class_exists($class, false)){..}

Your are calling your load_library method this way :
lev::load_library('lev_unit_tester/lev_base_test');
Which means you are testing, with class_exists(), if there is a class called lev_unit_tester/lev_base_test -- which is probably not quite the case : that's not a valid name for a class.
So class_exists() returns false ; and, so, you try to include the file that contains your class every time the load_library method is called.
There is no problem when you are using autoloading, because PHP will only call your autoloader when it you try to use a class which has not been defined : once the file that correspond to a class has been included, the autoloaded will not be called for that class again.

Related

phpunit issues instantiating new class for testing - "error loading class file" for unrelated classes

I'm trying to test my message class, but when I run phpunit I get three errors in the console:
1) messageClassTest::testCanBeCreatedFromMessageIDAndFBMPageAccessToken
error loading class file: /Users/ads/org/repo/classes/PHPUnit/DbUnit/TestCase.php
error loading class file: /Users/ads/org/repo/classes/Symfony/Component/Yaml/Yaml.php
error loading class file: /Users/ads/org/repo/classes/Composer/Autoload/ClassLoader.php
Undefined index: fallback
/Users/ads/org/repo/classes/message.php:47
/Users/ads/org/repo/classes/message.php:170
/Users/ads/org/repo/ci_tests/messageClassTest.php:18
The error exists when I instantiate the Message class, which is completely unrelated to the classes in the error log, and it works perfectly in the class file when I instantiate it the same way there.. what am I doing wrong?
Also, the other three errors below pointing to the message class file are non-fatal errors about an empty value not present in an array, so I don't think my trouble is there.
Here is my unit test file:
<?php
// backward compatibility
if (!class_exists('\PHPUnit\Framework\TestCase') &&
class_exists('\PHPUnit_Framework_TestCase')) {
class_alias('\PHPUnit_Framework_TestCase', 'PHPUnit\Framework\TestCase');
}
require_once __DIR__ . '/../classes/message.php';
class messageClassTest extends PHPUnit\Framework\TestCase {
private $message;
public function setup() {
$FBM_PAT = "token";
$this->message = Message::createNewMessage(1, $FBM_PAT);
}
public function testCanBeCreatedFromMessageIDAndFBMPageAccessToken()
{
$class = Message::class;
$message = $this->message;
$this->assertInstanceOf($class, $message);
}
}
?>
Also, I instantiated the message object in the way suggested by this other Stack Overflow post:
PHPUnit: include class after mocking it
Answered my own question - I guess the undefined index was not a fatal error for testing the actual class in it's own file, but it was a fatal error for phpunit. I just added a conditional check for if the fallback value exists, in the class file, and it fixed my problem... :D

Calling function in PHP class not working

I have a a class stored in path plug/PHPDocumentParser/DocumentParser.php:
namespace LukeMadhanga;
class DocumentParser {
static function parseFromString($string) {
// do stuff
}
}
I want to call the class and function. I run this in a file that's stored at the base folder:
include_once("plug/PHPDocumentParser/DocumentParser.php");
$docObj = new DocumentParser();
$docText = $docObj->parseFromString('hello world');
I receive this error:
Fatal error: Class 'DocumentParser' not found
I am pretty sure the problem is how I call the class, correct?
You are calling static function in wrong way. Try
DocumentParser::parseFromString()
Also use require_once, you will know if it was included correctly. (maybe path is wrong.)
Edit : Ok, you added namespace now - it should be \LukeMadhanga\DocumentParser::parseFromString() thats also why you dont get instance of DocumentParser using new.
Of course you can always add use keyword at top of your file to include your namespace.

spl_autoload_register - how to prevent fatal errors

I have the following function to load my libraries:
function load_class($name) {
$namePath = explode('_', $name);
$filePath = '';
if (is_array($namePath)) {
for ($i=0; $i<sizeof($namePath); $i++) {
$filePath .= $namePath[$i];
if ($i != sizeof($namePath) - 1) $filePath .= '/';
}
} else $filePath = $name;
if (is_file($filePath . '.php')) require_once($filePath . '.php');
else if (is_file($filePath . '.class.php')) require_once($filePath . '.class.php');
else throw new Exception('Unable to load class: ' . $name . '. No such file or a directory. ');
if (!class_exists($name)) throw new Exception('Class: ' . $name . ' doesn\'t exists. ');
}
And autoload:
function __construct() {
try {
spl_autoload_register(array($this, 'load_class'));
} catch (Exception $e) {
echo $e -> getMessage();
}
}
But unfortunatelly exceptions doesn't prevent me from getting fatal errors like there is no class or there is no file. Is there an elegant way to just show user my own communicate, not the php error?
One thing: spl_autoload_register does not throw exceptions. So there simply is no need to wrap that call into a try/catch - it won't ever happen to do anything! The only thing it returns is a boolean: true on success, or false on failure, which will probably only happen if you try to register a function that does not exist, or you pass something that is not callable.
The second thing: Be a nice citizen, do not cancel the autoloading process in your own function! Should you or anyone else use your autoloader together with a second one, like it would be the case if any other library with it's own autoloader is in use, then ALL these autoloaders might get called with the classname, and ONLY the one responsible for that kind of class must load it.
So if your autoloader cannot load the class, it must do nothing. Not throw any exception, not trigger an error. PHP will call another autoloading function after yours if it is defined, and if not, you'll get that nasty "Fatal error: Class 'Foobar\InexistentClass' not found". And this is a good thing because you were using a class that couldn't be loaded - either because of a typo, or an error in the autoloader, or some other reason.
One more thing: You really don't have to use require_once() for the loading. The autoloader will only be triggered ONCE to load a class. require_once() has a performance penalty because PHP must check if the file has been loaded before - and this check will NEVER prevent a second loading, because the autoloader will never be called a second time for an already known class.
How to prevent fatal errors if classes cannot be loaded? Impossible! In theory the autoloader could be coded to run eval() tp create the required class as an empty code fragment without any functions, or maybe even with designated __set, __get and __call magic functions that would intercept any usage, but what would that help? Your code required a class that does something, and that class cannot be found! This really IS a fatal error, and should be resolved, not hidden.
Last suggestion: Go with the PSR-0 autoloading standard. There are plenty of autoloaders already existing, and it is the defacto standard for any decent library. It will make everbodys life so much easier.
Update:
You can install your own error handler that is executed on PHP errors: set_error_handler() But this won't help with fatal errors.

php OOP - call static method from another class within class

I have the following class to another class in my main class.
class Products
{
public function __get( $key ){
return trim(functions::mssql_escape_string_rev($this->fields[ $key ]));
}
}
This beings back error: Call to undefined method functions::mssql_escape_string_rev()
Is there something wrong with my syntax or can this not be done?
Below is code used to autoload classes, this works for everything else so I know there is nothign wrong with the code. It just doesnt seem to initiate within the class.
// autoloader function called when we try to instantiate a class but haven't included the file
function __autoload($resource_name){
$resource_name = trim($resource_name);
try {
$filepath = CLASS_PATH."/class.".$resource_name.".inc.php";
if(#!include($filepath)){
throw new Exception('');
}
} catch(Exception $e) {
exit("Could not find the required file: ".$resource_name);
}
}
*******EDIT*****
Please ignore this, I made a stupid mistake and included the functions::mssql_escape_string_rev twice. Sorry for timewasting..
As the error says the problem is that functions::mssql_escape_string_rev() is not defined.
Since we can't see what you think is the definition we can not really help you.
For me it looks like the call should be Functions::mysql_escape_string_rev() with capital F and mysql.
Update
Calling static functions from another class works normally: http://codepad.org/wrfm5X7j
Maybe you are calling mysql_escape_string_rev before you included the functions class.

PHP Method Disappears?

I am including one PHP script into another using PHP's require_once() method. This script contains a class, TemplateAdmin, which instantiates itself right after the script, like this:
class TemplateAdmin {
// Class body...
}
$templateAdmin = new TemplateAdmin();
This was working fine for a while. However, I have adopted a new importing technique to include classes and packages. I have tested this new technique, and it works! However, for some strange reason, none of the methods in any of the classes I import are there when I need them. However, it seems as though the instance variables are still there.
For example, when a class with this absolute path is called:
require_once("C:\wamp\www\wave_audio\system\server\templates\TemplateAdmin.php");
... I get this error in the call stack:
Fatal error: Call to undefined method stdClass::top() in C:\wamp\www\wave_audio\cms\index.php on line 189
This error is referring to my use of the top() method inside of the TemplateAdmin class.
Does any one have any idea as to why this is happening??? If this helps, I have been using require_once() all along, I am running PHP 5.3.5 on a Windows XP Media Center machine.
Thank you for your time!
Assuming you dont want to use globals here is one way that only requires a few changes.
TemplateAdmin.php:
class TemplateAdmin {
// Class body...
}
return new TemplateAdmin();
Return include once in import:
function import($classes) {
//Convert ECMAScript style directory structures to Unix style
$address = str_replace(".", "/", $classes);
$address = INSTALL_ROOT . "system/server/" . $address . ".php";
if (file_exists($address) && is_file($address)) {
return require_once($address);
} else {
die(""" . $classes . "" does not link to an existing class");
}
}
Assign the variable:
$adminTemplate = import('templates.TemplateAdmin');
I have a feeling your php error message is accurate. I know on your stripped down version, you pieced it together how you're sure it's setup but it's obviously not a direct copy/paste since it's like:
class TemplateAdmin {
public function top() {
//The "top" method...
}
}
So, the error message says that the method "top" is not defined. If it were not including your file properly, it would tell you that the class you instantiated doesn't exist. Either that method does not exist in the class you think it is, or the method has been unset somewhere in that object instance. Trust your error message.

Categories