Instantiating a class within a recursive function in PHP - php

I've been creating a script using PHP and seem to have hit a brick wall at the moment with it. I'm trying to call a variable from another file which is within a class, so I went about it by including the file within the original and then instantiating the class to call the variable. But the entire thing is within a recursive function and I get Fatal error: Cannot redeclare class JVersion. I've pasted part of the code below:
...
function functionname($path)
{
...
define('_JEXEC', true);
require_once ($path ."libraries/cms/version/version.php");
$test_class = new JVersion();
$jma_ver = $test_class->getShortVersion();
...
functionname($path);
...
}
This is how the part of the code within the version.php looks like
defined('_JEXEC') or die;
final class JVersion
{
public $RELEASE = '2.5';
public $DEV_LEVEL = '1';
public function getShortVersion()
{
return $this->RELEASE.'.'.$this->DEV_LEVEL;
}
Is there a way I can overcome the "Fatal error: Cannot redeclare class JVersion" error ?

If I understand the problem correctly (i.e. you have many classes named JVersion that you need to use), then I'm not sure of any way around this problem without namespacing your JVersion classes in some way. Either give them distinct names or put them in different PHP namespaces.
This sounds more like an architectural problem, really; the code you're using doesn't seem to provide a way of getting its version in a disposable manner (without setting yourself up for conflicts like this). Ideally, you should just have a global JVersion class that can be insantiated with the appropriate version numbers; this way there'd be no class name conflicts.

Related

Add multiple class files before executing PHP [duplicate]

I'm new to PHP, so for example if I have a parent file that include the 2 child files:
include_once('includes/child1.php');
include_once('includes/child2.php');
If child2.php have a class Test with a function test_function:
class Test
{
static function test_function() {
}
}
then can we access this test_function in child1.php like this?
public static function initialize() {
Test::test_function()
}
and if it can, why does it not produce an error since child1.php is included before child2.php(note: I'm coming from Javascript perspective)
No code in child1 or child2 is actually being called. You're just defining some classes and functions, but nothing is calling any of these functions. Test::test_function() is never ever being evaluated, hence it cannot throw any error.
In general: yes, order matters. Everything you're trying to call needs to be defined before you call it. In this case, you're not calling anything, hence it's irrelevant.
Each file should take care of its own dependencies. I.e., child1.php should include (or better: require) child2.php itself if its code depends on it. Don't put the burden of including dependencies on the eventual user of child1.php, this just makes things extremely complicated.
In fact, you should be using autoloading, which will include all necessary files just in time as needed without you having to worry about the complexities of multiple include statements.
You can think of the include family ( include_once, require, require_once ) as a cut and paste type operation. If you follow just envision php creating one big file, pasting the content from each include call ( in the top down order of execution ).
So you might have
index.php
includes.php
functions.php
And if you do this in index
include 'includes.php'
some_function();
And then in includes.php
include 'functions.php'
And then in functions php you have a function some_function(){} you can use this in the index file after the include, php will see it like this
include 'includes.php'
include 'functions.php'
some_function(){}
some_function();
In your example above you would not be able to call the class because you are calling it before including it. Like this
//include_once('includes/child1.php');
Test::test_function();
//include_once('includes/child2.php');
class Test
{
static function test_function() {
}
}
However that said I notice you defined a "method" around your call to Test::test_function() that method would need to be wrapped in a class to work, if that was the intended way then it depends when you instantiate that class, you must do that after the Test class is defined. So for that case we will assume that that method is in a class
class Test2{
public static function initialize() {
Test::test_function()
}
}
Now if you use this class back inside of the parent file or anywhere after the include of child2.php then it will work, so in the parent file if you do this.
include_once('includes/child1.php');
include_once('includes/child2.php');
Test2::initialize();
You would think of this as a big file like this
class Test2{
public static function initialize() {
Test::test_function()
}
}
class Test
{
static function test_function() {
}
}
Test2::initialize();
It should be fine. You just cant call it before it is defined. Make sense?
All that said, I would strongly suggest looking into a PSR autoloader, that is the standard way of including classes these days.
Here is a good post on the topic
http://www.sitepoint.com/autoloading-and-the-psr-0-standard/
Update explination
I'll try to make this as simple as I can. The way PHP works is it loads a file and parses the code, this basically means it just checks the formatting for syntax errors or typos and any new functions or class definitions ( it only registers the names of that new stuff and checks the syntax ). Once that is done and passes it starts to execute the code from top to bottom.
Now when including a file it can't parse it right away because it needs to execute the includes, which it does not do during the initial parsing. After it runs the include it parses the new chunk of code, and then continues executing that new code from top to bottom until the end of the included file at which point it returns to the original file and continues on from the include deceleration.
So while it seems different that you can run a function before defining it in the same file, but not in an included file, it is actually the same behavior. This is because it needs to execute the file to know the functions or code that is in it. So if you call the function before the include, PHP hasn't had a chance to even look in the file yet. Some of this is because you could put an include in an if statement and then PHP would not need to include the file.
What it doesn't do is, parse the file run all the includes and then run the code. I hope that clarified how the process flow works.

strange Fatal error: Cannot redeclare class paradox [duplicate]

Does anyone know what can cause this problem?
PHP Fatal error: Cannot redeclare class
You have a class of the same name declared more than once. Maybe via multiple includes. When including other files you need to use something like
include_once "something.php";
to prevent multiple inclusions. It's very easy for this to happen, though not always obvious, since you could have a long chain of files being included by one another.
It means you've already created a class.
For instance:
class Foo {}
// some code here
class Foo {}
That second Foo would throw the error.
That happens when you declare a class more than once in a page.
You can fix it by either wrapping that class with an if statement (like below), or you can put it into a separate file and use require_once(), instead of include().
if (!class_exists('TestClass')) {
// Put class TestClass here
}
Use include_once(); - with this, your codes will be included only one time.
This will happen if we use any of the in built classes in the php library. I used the class name as Directory and I got the same error. If you get error first make sure that the class name you use is not one of the in built classes.
This error might also occur if you define the __construct method more than once.
Sometimes that happens due to some bugs in PHP's FastCGI.
Try to restart it. At Ubuntu it's:
service php-fastcgi restart
I had the same problem while using autoload like follows:
<?php
function __autoload($class_name)
{
include $class_name . '.php';
}
__autoload("MyClass1");
$obj = new MyClass1();
?>
and in other class there was:
namespace testClassNamespace;
class MyClass1
{
function __construct()
{
echo "MyClass1 constructor";
}
}
The sollution is to keep namespace compatibility, in my example namespace testClassNamespace; in both files.
Just adding;
This error can also occur if you by mistake put a function inside another function.
PHP 5.3 (an I think older versions too) seems to have problem with same name in different cases. So I had this problem when a had the class Login and the interface it implements LogIn. After I renamed LogIn to Log_In the problem got solved.
Just do one thing whenever you include or require filename namely class.login.php. You can include it this way:
include_once class.login.php or
require_once class.login.php
This way it never throws an error.
This function will print a stack telling you where it was called from:
function PrintTrace() {
$trace = debug_backtrace();
echo '<pre>';
$sb = array();
foreach($trace as $item) {
if(isset($item['file'])) {
$sb[] = htmlspecialchars("$item[file]:$item[line]");
} else {
$sb[] = htmlspecialchars("$item[class]:$item[function]");
}
}
echo implode("\n",$sb);
echo '</pre>';
}
Call this function at the top of the file that includes your class.
Sometimes it will only print once, even though your class is being included two or more times. This is because PHP actually parses all the top-level classes in a file before executing any code and throws the fatal error immediately. To remedy this, wrap your class declaration in if(true) { ... }, which will move your class down a level in scope. Then you should get your two traces before PHP fatal errors.
This should help you find where you class is being included from multiple times in a complex project.
Did You use Zend Framework? I have the same problem too.
I solved it by commenting out this the following line in config/application.ini:
;includePaths.library = APPLICATION_PATH "/../library"
I hope this will help you.
Another possible culprit is source control and unresolved conflicts. SVN may cause the same class to appear twice in the conflicted code file; two alternative versions of it ("mine" and "theirs").
I have encountered that same problem:
newer php version doesn't deal the same with multiple incluse of the same file (as a library), so now I have to change all my include by some include_once.
Or this tricks could help, if you d'ont have too much class in your library...
if( class_exists('TestClass') != true )
{
//your definition of TestClass
}
I had the same problem "PHP Fatal error: Cannot redeclare class XYZ.php".
I have two directories like controller and model and I uploaded by mistakenly XYZ.php in both directories.(so file with the same name cause the issue).
First solution:
Find in your whole project and make sure you have only one class XYZ.php.
Second solution:
Add a namespace in your class so you can use the same class name.
It actually means that class is already declared in the page and you are trying to recreate it.
A simple technique is as follow.
I solved the issue with the following. Hope this will help you a bit.
if(!class_exists("testClassIfExist"))
{
require_once("testClassIfExist.php");
}
i have encountered that same problem. found out the case was the class name. i dealt with it by changing the name. hence resolving the problem.
You must use require_once() function.

Identifying class names from $_SERVER['SCRIPT_FILENAME']

What is the best way to obtain the class name for a requested PHP file if my unknown class follows the following pattern?
index.php
<?php
require_once("startup.php");
class NotIndex extends View
{
public function getView()
{
echo "<pre>View Data</pre>";
}
}
?>
For testing I want to create an instance of the NotIndex class within the startup.php script.
startup.php
<?php
require_once("view.php");
//Include the script again to bring in the class definition
include($_SERVER['SCRIPT_FILENAME']);
//Make sure I'm seeing any errors
error_reporting(E_ALL);
ini_set('display_errors','On');
//If I knew the class I could just do this
$Page = new NotIndex();
$Page->getView();
//Todo: Find the class from $_SERVER['SCRIPT_FILENAME']
//Todo: Once we find the class create an instance and call getView()
exit;
?>
view.php
<?php
abstract class View
{
abstract function getView();
}
?>
I'm thinking a regular expression solution might be simple since the desired data will always be between 'class' and 'extends'. I don't have much experience formulating the desired expression and would appreciate some insight.
The following solution may or may not be a good way of doing this, but it did lead me to a non-regular expression solution which is always a plus. If anyone can improve on this, then I will gladly give them credit for both my questions above. Credit actually goes to #Nik answering Stack Overflow question Extracting function names from a file (with or without regular expressions). If I do this in my startup script then I can probably count on the unknown class being the last one in the array. However, I plan on integrating this into my framework and would like a more complete solution.
Since the class name is unknown, you may ask how can we be sure? Well, the abstract class View comes right before the unknown class in the array. Any solution would surely have to check for this. So without guarantee the last class is the needed class, I probably need to traverse backwards in the array until I have identified the abstract View class and the previous value in the array would be the unknown subclass.
startup.php
<?php
require_once("view.php");
//Include the script again to bring in the class definition
include($_SERVER['SCRIPT_FILENAME']);
//Make sure I'm seeing any errors
error_reporting(E_ALL);
ini_set('display_errors','On');
//If I knew the class I could just do this
$Page = new NotIndex();
$Page->getView();
//Todo: Find the class from $_SERVER['SCRIPT_FILENAME']
//Todo: Once we find the class create an instance and call getView()
$Classes = get_declared_classes();
$ViewObject = array_pop($Classes);
$NewPage = new $ViewObject();
$NewPage->getView();
exit;
?>
View Data
Please expand any opinions on this usage.
So this solution only works if I include my abstract View class immediately before I include the unknown subclass script again via include($_SERVER['SCRIPT_FILENAME']);. So this implies the get_declared_classes() function adds the classes in the order they were defined or included. This could be a problem.
<?php
require_once("view.php");
//Include the script again to bring in the class definition
include($_SERVER['SCRIPT_FILENAME']);
include("killsolution.php");
//Make sure I'm seeing any errors
error_reporting(E_ALL);
ini_set('display_errors','On');
//If I knew the class I could just do this
$Page = new NotIndex();
$Page->getView();
//Todo: Find the class from $_SERVER['SCRIPT_FILENAME']
//Todo: Once we find the class create an instance and call getView()
$Classes = get_declared_classes();
$ViewObject = array_pop($Classes);
$NewPage = new $ViewObject();
$NewPage->getView();
exit;
?>
Fatal error: Call to undefined method
killsolution::getView()
(This question is a subset of another open Stack Overflow question, What are some PHP object-oriented framework initialization techniques?)
Use __autoload().
If you must continue down this path then you can use PHPs Tokenizer to obtain the class name from a file path. Regex is not really the answer to this problem.
A friend of mine has written Überloader (A brute-force autoloader for PHP5.) which uses this very technique when it indexes class files. The _check_file() method from it will be of particular interest to you.
Using Überloader itself may even be a far better solution to your problem. It maintains a cache of class names and their relevant file paths so it is quicker than using the Tokenizer on each page load. Überloader is designed for legacy projects that have not planned or thought about their class naming conventions or file structures.
The following solution allows you to iterate over classes defined at runtime and in my case search for a user defined subclass of View. The get_declared_classes() function will return both system and user defined classes in the order they were included. My system contained over 120 system classes before the requested script class was included. For this reason I iterate backwards in the returned array.
startup.php
//Include the script again to bring in the class definition
include($_SERVER['SCRIPT_FILENAME']);
//Make sure I'm seeing any errors for testing
ini_set('display_errors','On');
//Don't assume we will find a subclass of View
$RequestClass = false;
//Iterate over declared classes starting from the last defined class
for($i = count($classes = get_declared_classes()) - 1; $i >= 0; $i--)
{
//Test if unknown class is a subclass of abstract View
if(get_parent_class($classes[$i]) == 'View')
{
//Store the name of the subclass of View
$RequestClass = $classes[$i];
//We found our unknown View
break;
}
}
if($RequestClass)
{
//We can now instantiate the class or do something useful
$Page = new $RequestClass();
$Page->getView();
}
exit;
Depending on when you call the get_declared_classes() function, the array could change. I know my unknown class will always be a subclass of View, therefore I can identify it no matter how many classes are defined afterwards. However, just to elaborate, if we have an unknown class that does not extend another class, then we can still obtain the last defined class using:
$LastClass = array_pop(get_declared_classes());
So we can always find the requested page's class if we search for it immediately after it is defined. Theres alot of ways this will break, but most people I suspect will never need this functionality anyways.

Can PHP __autoload() a class from within another __autoload() of the same class?

OK, this is a tough one... I think, and I have a feeling the answer is simply no, but in that case I would like some answers for alternatives.
I have a very complex __autoload() function in a framework which can dynamically create classes. There a three classes required in order for the dynamic creation of a class called AuthActions -- these three are: fRecordSet, RecordSet, and AuthAction (note there's no S on that one).
My autoloader will look for a static method "init" on any class it loads and try to run that. On my ActiveRecord class it attempts to use AuthActions in order to get a list of supported actions on a particular active record. AuthAction (no S) also calls AuthActions within it's init, so basically the Active Record is loaded, and tries to load AuthActions, triggering the loading of the other three, and then when it finishes loading AuthAction still within the original autoloader AuthAction tries to call AuthActions which triggers another autoload since the original one did not complete yet.
This causes the following which has some echo statements to clarify:
Attempting to load ActiveRecord
Attempting to load fActiveRecord
fActiveRecord loaded via /var/www/dotink.org/inkwelldemo/inc/lib/flourish
ActiveRecord loaded via /var/www/dotink.org/inkwelldemo/inc/lib
Attempting to load AuthActions
Attempting to load RecordSet
Attempting to load fRecordSet
fRecordSet loaded via /var/www/dotink.org/inkwelldemo/inc/lib/flourish
RecordSet loaded via /var/www/dotink.org/inkwelldemo/inc/lib
Attempting to load AuthAction
AuthAction loaded via /var/www/dotink.org/inkwelldemo/models
Fatal error: Class 'AuthActions' not found in /var/www/dotink.org/inkwelldemo/models/AuthAction.php on line 24
The problem here is that the subsequent call to __autoload('AuthActions') would succeed because the three classes it requires are now in place... but it seems to die on the premise alone that it's already trying to autoload 'AuthActions' -- this seems to be hardwrit into PHP.
In testing this I found the following will loop forever with no error:
function __autoload($class) {
__autoload($class);
}
$foo = new Bar();
While this one below will error similarly:
function __autoload($class) {
$test = new Bar();
}
$foo = new Bar();
This behavior seems inconsistent as essentially they should amount to the same thing (kinda). If PHP internally triggered autoloads acted like a user call to __autoload() I don't think I would have a problem (or if I did the then it would be a problem of it looping forever which would be a separate issue of determining why the class wasn't getting loaded to resolve the dependencies).
In short, I need a way to either recursively loop the autoloader like this based on PHP triggered autoloads... is this simply not possible? Is it a bug in my particular version possibly? It seems to be affecting 5.2.6 - 5.3.2 in my tests, so I can't imagine it's a bug overall.
Update:
The code for the init method() on AuthAction is below:
/**
* Initializes the AuthAction model
*
* #param array $config The configuration array
* #return void
*/
static public function init($config) {
// Establish permission definitions and supported actions
$every_permission = 0;
$supported_actions = array();
foreach (AuthActions::build() as $auth_action) {
$action_name = $auth_action->getName();
$action_value = intval($auth_action->getBitValue());
$every_permission = $every_permission | $action_value;
$supported_actions[] = $action_name;
define(self::makeDefinition($action_name), $action_value);
}
define('PERM_ALL', $every_permission);
}
You can see where it is calling AuthActions as a separate class, and mind you it is only because it is being loaded within the original attempt to load that it fails. I can obviously remove this code and it will work -- the original load of AuthActions will complete successfully as all the pre-requisite classes are then loaded.
That said, init() is the most appropriate place for this code, and even if I am unable to use inter-dependent classes which haven't been loaded yet within init() I would still prefer to keep that functionality. Any alternative way of implementing that functionality would be great... Ideally PHP would have events for such things where you could for example register a callback when say an "autoloaded" event is triggered. This would allow the code to run AFTER the original autoload and would resolve this seemingly meaningless restriction.
Now with that said, any suggestions how to automatically call init() on a class every time it is loaded are appreciated and welcome.
__autoload method only gets called when you are are trying to use a class/interface which hasn't been defined yet.
Therefore with your example
function __autoload($class) {
$test = new Bar();
}
$foo = new Bar();
You are attempting to load the class bar which has not been required/requiered_once therefore the class is not defined so it calls the __autoload method as a last resort then within the autoload you are again trying to load the same class which has not been defined.
The correct way to use the __autoload would be as shown in the php site.
<?php
function __autoload($class_name) {
require_once $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
And all your init stuff can be put in __constructor can't it?
unless i'm missing something from your question...
I think this
My autoloader will look for a static
method "init" on any class it loads
and try to run that.
is the key to your problem. Your autoloader shouldn't be running anything, it should be including (or otherwise defining) the class and nothing else.
What sort of code are you trying to run when a class is defined (ie. in your static "init" method)?

PHP Fatal error: Cannot redeclare class

Does anyone know what can cause this problem?
PHP Fatal error: Cannot redeclare class
You have a class of the same name declared more than once. Maybe via multiple includes. When including other files you need to use something like
include_once "something.php";
to prevent multiple inclusions. It's very easy for this to happen, though not always obvious, since you could have a long chain of files being included by one another.
It means you've already created a class.
For instance:
class Foo {}
// some code here
class Foo {}
That second Foo would throw the error.
That happens when you declare a class more than once in a page.
You can fix it by either wrapping that class with an if statement (like below), or you can put it into a separate file and use require_once(), instead of include().
if (!class_exists('TestClass')) {
// Put class TestClass here
}
Use include_once(); - with this, your codes will be included only one time.
This will happen if we use any of the in built classes in the php library. I used the class name as Directory and I got the same error. If you get error first make sure that the class name you use is not one of the in built classes.
This error might also occur if you define the __construct method more than once.
Sometimes that happens due to some bugs in PHP's FastCGI.
Try to restart it. At Ubuntu it's:
service php-fastcgi restart
I had the same problem while using autoload like follows:
<?php
function __autoload($class_name)
{
include $class_name . '.php';
}
__autoload("MyClass1");
$obj = new MyClass1();
?>
and in other class there was:
namespace testClassNamespace;
class MyClass1
{
function __construct()
{
echo "MyClass1 constructor";
}
}
The sollution is to keep namespace compatibility, in my example namespace testClassNamespace; in both files.
Just adding;
This error can also occur if you by mistake put a function inside another function.
PHP 5.3 (an I think older versions too) seems to have problem with same name in different cases. So I had this problem when a had the class Login and the interface it implements LogIn. After I renamed LogIn to Log_In the problem got solved.
Just do one thing whenever you include or require filename namely class.login.php. You can include it this way:
include_once class.login.php or
require_once class.login.php
This way it never throws an error.
This function will print a stack telling you where it was called from:
function PrintTrace() {
$trace = debug_backtrace();
echo '<pre>';
$sb = array();
foreach($trace as $item) {
if(isset($item['file'])) {
$sb[] = htmlspecialchars("$item[file]:$item[line]");
} else {
$sb[] = htmlspecialchars("$item[class]:$item[function]");
}
}
echo implode("\n",$sb);
echo '</pre>';
}
Call this function at the top of the file that includes your class.
Sometimes it will only print once, even though your class is being included two or more times. This is because PHP actually parses all the top-level classes in a file before executing any code and throws the fatal error immediately. To remedy this, wrap your class declaration in if(true) { ... }, which will move your class down a level in scope. Then you should get your two traces before PHP fatal errors.
This should help you find where you class is being included from multiple times in a complex project.
Did You use Zend Framework? I have the same problem too.
I solved it by commenting out this the following line in config/application.ini:
;includePaths.library = APPLICATION_PATH "/../library"
I hope this will help you.
Another possible culprit is source control and unresolved conflicts. SVN may cause the same class to appear twice in the conflicted code file; two alternative versions of it ("mine" and "theirs").
I have encountered that same problem:
newer php version doesn't deal the same with multiple incluse of the same file (as a library), so now I have to change all my include by some include_once.
Or this tricks could help, if you d'ont have too much class in your library...
if( class_exists('TestClass') != true )
{
//your definition of TestClass
}
I had the same problem "PHP Fatal error: Cannot redeclare class XYZ.php".
I have two directories like controller and model and I uploaded by mistakenly XYZ.php in both directories.(so file with the same name cause the issue).
First solution:
Find in your whole project and make sure you have only one class XYZ.php.
Second solution:
Add a namespace in your class so you can use the same class name.
It actually means that class is already declared in the page and you are trying to recreate it.
A simple technique is as follow.
I solved the issue with the following. Hope this will help you a bit.
if(!class_exists("testClassIfExist"))
{
require_once("testClassIfExist.php");
}
i have encountered that same problem. found out the case was the class name. i dealt with it by changing the name. hence resolving the problem.
You must use require_once() function.

Categories