PHP: cannot declare class because the name is already in use - php

I have 5 scripts:
database.php
parent.php
child1.php
child2.php
somescript.php
parent.php class looks like this:
include 'database.php';
class Parent {
public $db;
function __construct() {
$this->db = new Database();
}
}
The child1.php and child2.php classes looks like this:
include 'parent.php';
class Child1 extends Parent {
function __construct() {
parent::__construct();
}
function useDb() {
$this->db->some_db_operation();
}
}
The problem
When I try to include both child1 and child2 in somescript.php, it returns the following error:
cannot declare class Database because the name is already in use in
database.php on line 4 (this is the line which contains words 'class Database')
But if I include only a single file (child1 or child2), it works great.
How do I correct that?

You want to use include_once() or require_once(). The other option would be to create an additional file with all your class includes in the correct order so they don't need to call includes themselves:
"classes.php"
include 'database.php';
include 'parent.php';
include 'child1.php';
include 'child2.php';
Then you just need:
require_once('classes.php');

try to use use include_onceor require_once instead of include or require

Another option to include_once or require_once is to use class autoloading. http://php.net/manual/en/language.oop5.autoload.php

You should use require_once and include_once. Inside parent.php use
include_once 'database.php';
And inside child1.php and child2.php use
include_once 'parent.php';

Class Parent cannot be declared because it is PHP reserved keyword so in effect it's already in use

I had this problem before and to fix this,
Just make sure :
You did not create an instance of this class before
If you call this from a class method, make sure the __destruct is set on the class you called from.
My problem (before) :
I had class : Core, Router, Permissions and Render
Core include's the Router class, Router then calls Permissions class, then Router __destruct calls the Render class and the error "Cannot declare class because the name is already in use" appeared.
Solution :
I added __destruct on Permission class and the __destruct was empty and it's fixed...

Related

Importing custom class inside a controller

I created a class at Controller folder of Cake project like this:
<?php
class Hi
{
function __construct(){ }
public function hi()
{
echo "hi!";
exit;
}
}
Then in a controller, I tried to include it:
<?php
namespace App\Controller;
use App\Controller\AppController;
include_once "Hi.php";
class MyController extends AppController
{
public function sayHi()
{
$a = new Hi();
$a.hi();
}
}
Here is the error I'm having:
Fatal error: Cannot declare class Hi, because the name is already in use in path\api\src\Controller\Hi.php on line 2
What's going on?
MyController.php and Hi.php are in the same folder. I'm using PHP 7.
Including a file won't make the classes in that file part of the current namespace, as namespaces are a per-file functionality.
http://php.net/...namespaces.importing.php#language.namespaces.importing.scope
Your Hi class will be declared in the global namespace, and your new Hi() will cause PHP to look for it in the current namespace, ie it will look for App\Controller\Hi, which doesn't exist, hence the composer autoloader kicks in, and will map this via a PSR-4 namespace prefix match to src/Controller/Hi.php, which will include the file again, and that's when it happens.
http://www.php-fig.org/psr/psr-4/
Long story short, while using new \Hi() would fix this, you better not include class files manually, or declare them in paths where they do not belong. Instead declare your files and classes in a proper autoloading compatible fashion, that is for example with a proper namespace in a path that matches that namespace, like
namespace App\Utils;
class Hi {
// ...
}
in
src/Utils/Hi.php

Are namespaces in PHP "inherited"?

EDIT:
Yes the problem was using \ at the beginning of the use statement. As M1ke pointed out, use goes from the root element.
Original post
I think is a PHP question but it may be Drupal.
I'm working on a headless Drupal project where is using a class (which I call Entity Model) that uses a Drupal class called EntityFieldQuery.
Before a create or use this class I bootstrap Drupal using:
require_once DRUPAL_ROOT.'/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
The entity model class is in the Models names space like so:
namespace Models;
use \EntityFieldQuery;
class EntityModel
{
.....
$query = new EntityFieldQuery();
$query->doSomething();
......
}
The EntityFieldQuery is found perfectly as I use the "\" because this class is out of the Models namespace.
The problem is when this class is created is uses other classes that don't use any namespace, and I have the following error:
class Models\InsertQuery not found in ....
Here is the class used by EntityFieldQuery that uses InsertQuery
class InsertQuery_mysql extends InsertQuery ...
I don't understand why InsertQuery_mysql is found but InsertQuery
I ended up adding a "\" in InsertQuery to fix the problem like so:
class InsertQuery_mysql extends \InsertQuery ...
Actually this class in a php file called query.inc that contains two defitinion classes (in the same file, I don't know this is a a problem too)
class InsertQuery_mysql extends InsertQuery
....
class TruncateQuery_mysql extends TruncateQuery
I thought that if I use "new \ClassName()" the "default namespace" inside this class would be "\" too and not the first called class's namespace.
I don't like to modify 3rd party libraries, is any way to avoid this? I guess is a architecture problem rather than a lack of definition if someone has a better idea, I appreciate.
Thanks!
EDIT2: Adding more info...
In order of execution.
index.php:
require_once 'vendor/autoload.php';
require_once DRUPAL_ROOT.'/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
...
app/SiteController.php:
use Models\Campaign;
class SiteController {
...
$campaing = new Campaign();
...
app/Models/Campaing.php:
namespace Models;
class Campaign extends EntityModel {
...
app/Models/EntityModel.php:
namespace Models;
use \EntityFieldQuery; //<-- this should go without \ as I say in EDIT section
class EntityModel {
...
public function getAll() {
$query = new EntityFieldQuery(); //<--throwed Models\InsertQuery not found. It must have \ at the beginning of the class name.
To answer the base question (and pending further code) PHP namespaces are set by whichever namespace is declared in the file.
// Bar.php
namespace Foo;
class Bar {}
// some other file
use Foo\Bar;
$test = new Bar(); //works
// different file
namespace Foo;
$test = new Bar(); // works
// another file
require 'Bar.php';
// won't work because we are not in namespace "Foo"
$test = new Bar();
In your specific case it the use \EntityLoader should be use EntityLoader because you're exiting the namespace you want to be inside.

call different namespace or class from one in PHP

on index.php I have below code
require 'Bootstrap.php';
require 'Variables.php';
function __autoload($class){
$class = str_replace('Control\\', '', $class);
require_once 'class/'.$class.'.php';
}
$bootstratp = new Control\Bootstrap();
on Bootstrap.php
namespace Control;
class Bootstrap{
function __construct(){
Constructor::load_html();
self::same_namespace_different_class();
}
static function same_namespace_different_class(){
Variables::get_values();
}
}
in class/Constructor.php
class Constructor{
static function load_html(){
echo 'html_loaded';
}
static function load_variables(){
echo 'load variables';
}
}
and on Variables.php
namespace Control;
class Variables{
static function get_values(){
Constructor::load_variables();
}
}
Assume, In total I have 4 PHP files including 3 Class files of 2 different namespaces. I also have a __autoload function on index.php that will call classes from 'class' folder but my 'Control' namespace files are in root folder.
When I echo the class name in __autoload i get the all the class names starting with 'Control\' even when I am calling a class from global namespace.
I am getting below error
Warning: require_once(class/Variables.php): failed to open stream: No such file or directory in _____________ on line 10
what is wrong with my code??
When I echo the class name in __autoload i get the all the class names starting with 'Control\' even when I am calling a class from global namespace.
This is because in Bootstrap.php all the code is in Control namespace (namespace Control). So when you use:
Variables::get_values();
you call
\Control\Variables::get_values();
if you want to use Variables from global namespace you should use here:
\Variables::get_values();
Of course, the same happens for in Variables.php file:
Constructor::load_variables();
As Constructor is defined in global namespace (in class/Constructor.php there is no namespace used), you should access it here using:
\Constructor::load_variables();
If it's still unclear you could also look at this question about namespaces in PHP.
You should also notice that using __autoload is not recommended. You should use spl_autoload_register() now. Documentation about autoloading

PHP are included classes part of namespace or global?

I have been looking into name spaces recently. I am creating an MVC framework and want to try to move towards PHP 5.3+ features.
Lets say I define a namespace, call it \Controller.
I then want to include a file which has the class of Home.
namespace Controller;
include "class.home.php";
The file contents:
class.home.php:
class Home {
public function hello() {
}
}
In this example, will Home be a part of the Controller namespace? or part of the global namespace?
I want to be able to access Home like new \Controller\Home(); Will the code above work like that?
The namespace of a class depends on the namespace it was declared in, not in which it was included. If the latter was the case, it'd be impossible to clearly know what namespace something will be in.
If you did not write namespace Foo\Bar\Baz; at the top of the file in which you declare the class, the class is in the global namespace, always.
In your case Home will not be part of the Controller namespace, because you need to define the namespace inside of class.home.php like:
namespace Controller;
class Home {
public function hello() {
}
}
And than you can:
namespace Controller;
include "class.home.php";
new \Controller\Home();

PHP namespace calling functions from different directories

I am trying to get php's namespace technique down but having some issues here:
Why can I not call the method testA from class B? Also I would like to add that I am using 5.3.
in lib ->
<?php
namespace lib;
class A{
public static function testA(){
echo "I am inside A";
}
}
in root dir ->
<?php
class B{
public function showSomething(){
lib\A::testA();
}
$test = new B();
$test->showSomething();
Using namespace you only encapsulate item but not include it. I can't see including of the class file. Include it or use autoload.
Make sure you're including the file that holds your class A.

Categories