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.
Related
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
I'm trying to trick PHP into taking a class from another namespace when trying to create a specific class.
I have two class called "page", the first is in the Core namespace:
namespace Core;
class Page {...}
The second inherits from Core\Page, but adds a few things. It is in the Addons namespace.
namespace Addons;
class Page extends \Core\Page{...}
The reason I want to do this is because I want to build my system with an easy addon engine. Whenever I want, I can add a line in an XML file that tells the autoloading function to take the class in the addon namespace instead of the core namespace.
However, when I try to do this :
spl_autoload_register('loadClass');
public function loadClass(string $className)
{
if (Addon_exist_and_is_registered($className))
{
require "/Addons/$className.php";
}
else
{
require "/Core/$className.php";
}
}
$page = new \Core\Page(); <-- error here
I get an error saying that the class \Core\Page cannot be found in the file Addons\Page.php. This is normal behaviour since the class is not in the same namespace and as such, the fully qualified name cannot find the right class.
Is it possible to trick PHP into thinking that a child class in another namespace is actually the right class? I tried this for the addons class;
namespace Core;
class Page extends \Core\Page{...}
But it breaks the inheritance as you cannot inherit yourself.
Ignore that the classes have the "same name". Because they don't. One class is called Core\Page, the other is called Addons\Page. Those are their names, their fully qualified names to be exact. It's as much a difference as Foo and Bar. If you tell PHP to instantiate Core\Page, then it's going to do that; you can't "trick" it into instantiating Addons\Page, since that's an entirely different class name.
Don't try to "trick" anyone, make your system actually extensible and explicitly allow overriding of class names:
$class = 'Core\Page';
if (...) {
$class = 'Addons\Page';
}
$page = new $class;
I read up quite a bit on namespaces in PHP and I'm still confused.
I have a class in a different folder that is under the namespace Entity (Class A).
I have another class in a different folder that is under the same namespace (Class B), and extends class A.
I get an error saying class A could not be found.
My main question is - do I have to include class A when I create a new instance of class B?
This is my code:
(Class A)
namespace Entity;
//Framework/Entity/BaseModel.php
class BaseModel {
//TODO: IMPLEMENT THIS
public function GetList() {
return null;
}
}
(Class B)
namespace Entity;
//Models/Points.php
class Points extends BaseModel{
public $Id = null;
}
(Main File)
require_once(dirname(dirname(__FILE__)) . '/Models/Points.php');
$points = new Points();
Namespaces have nothing to do with actually including files, those are two completely separate mechanisms. So, yes, you will still have to require_once the file that the class is defined in before you can use it.
Having said that, especially with namespaces, autoloaders are typically used so you don't have to write a ton of require code. If you organise your class files in folders exactly as their namespaces are, it's very easy to autoload their files. See http://php.net/manual/en/language.oop5.autoload.php and https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
Parent class definition must be know on definition of child class.
Even before you create instance of child class.
How otherwise PHP would know what to put inside class you create?
require_once('BaseModel.php')
namespace Entity;
//Models/Points.php
class Points extends BaseModel{
public $Id = null;
}
I'm using php for my new project which is quite large. I feel the need to employ namespaces.
I have read many docs on it, but am confused practically about. Here is the scenario:
I have defined the following namespace and class:
namespace urlNS;
class URL
{
// content of the class
}
And then in another file, I want to define a class in the same namespace (urlNS) and also extend the URL class (which is a subset of urlNS namespace), and to do this, I have done:
namespace urlNS:
class Inc extends urlNS\url
{
// content
}
Now, I wanted to make use of a defined namespace twice (or even more), did I do it in a right way?
Base class definition:
<?php
namespace urlNS;
class URL {}
Subclass:
<?php
namespace urlNS;
class Inc extends URL {}
Using:
<?php
$url = new urlNS\URL();
$suburl = new urlNS\Inc();
Or with use keyword:
<?php
use urlNS\URL;
$url = URL();
I have been searching websites to try and get a handle on using PHP namespaces, but they all seem quite vague but what they're trying to do is easy to understand!
My question is: I have a file called people.php and in it is defined class called people. If I create another file called managers.php in the same folder can I define a class again called people which extends the original people class but in the namespace of managers, if so do I have to 'include' the original people.php and if so do I put the include after the writing: namespace managers?
Namespaces are a way to group your related classes in packages. What you describe could best be put under a single namespace like
<?php // people.php
namespace com\example\johnslibrary\people;
abstract class People {
}
and then
<?php // manager.php
namespace com\example\johnslibrary\people;
require_once 'path/to/People.php'; // can better use autoloading though
class Manager extends People {
}
because a Manager is a subclass of People, so there is not much of a reason to put them into their own namespace. They are specialized People.
If you want to Managers to be in their own namespace, you can do so, but have to use the fully qualified name when using the extends keyword, e.g.
<?php // manager.php
namespace com\example\johnslibrary\managers;
require_once 'path/to/People.php';
class Manager extends \com\example\johnslibrary\people\People {
}
or import the People class first
<?php // manager.php
namespace com\example\johnslibrary\managers;
use com\example\johnslibrary\People as People;
require_once 'path/to/People.php';
class Manager extends People {
}
See the PHP Manual on Namespaces for extensive documentation.
// people.php
<?php
namespace People;
class People {}
// managers.php
<?php
namespace Managers;
require_once __DIR__.'/people.php';
class People extends \People\People {}
I have old PHP Class and i need to use it in new PHP file as for example:index.php has to use iClass.php. But before using the OLD iClass.php i have to modify it as below, so that i can use it in index.php.
iClass.php:
namespace ic;
class iClass {
public static function callMeFromClass() {
echo 'OK - you have called me!';
exit;
}
}
index.php
namespace inex;
require_once 'iClass.php';
use ic\iClass;
iClass::callMeFromClass();