Import namespace in PHP - php

I have just started learning a PHP framework and using namespace and use. I have gone through some resources trying to understand them (https://code.tutsplus.com/tutorials/namespacing-in-php--net-27203). I think I get what namespace is but I do not quite understand how namespace importing (use keyword) work.
I get that namespace works like below. I have a lib.php file:
<?php
namespace namespaceproj\lib1;
class lib1 {
private $var;
function __construct(){
$this->var='Run from lib';
echo $this->var;
}
}
I have an index.php file
<?php
namespace main ;
include "lib.php";
class lib1 {
private $var;
function __construct(){
$this->var='run from main';
echo $this->var;
}
}
$obj=new \namespaceproj\lib1\lib1(); // this refers to the class with namespace namespaceproj\lib1;
$obj = new lib1();// this refers to the class with namespace main .
All fine and good now I am trying to use the use keyword. I use the namespace\classname in the use keyword and can instantiate the class directly. I am guessing the namespace of the class becomes main when we use "use".
<?php
namespace main ;
include "lib.php";
class lib1 {
private $var;
function __construct(){
$this->var='run from main';
echo $this->var;
}
}
//Accessing class using use
use namespaceproj\lib1\lib1 as lib1inc ;
$obj=new lib1(); //This refers to class with main namespace
$obj=new lib1inc(); // This refers to class with namespaceproj\lib1; namespace
*/
Now is the part I am not able to understand. What happens if you do not want to import classes individually but import many classes in a namespace? The resource say you can use the use keyword to import namespaces. So I try to import the namespace of the lib file and try to instantiate the object. If I try something like this
use namespaceproj\lib1 ;
$obj=new libnew();
It gives me an error saying:
Cannot use namespaceproj\lib1 as lib1 because the name is already in use in C:\xampp\htdocs\AllTest\index.php on line 26
I was guessing the namespaces and all classes in that namespaces was getting imported to the main namespace and hence the error .
So I used the as keyword
use namespaceproj\lib1 as libnew;
$obj=new libnew();
This gives me an error:
Fatal error: Class 'namespaceproj\lib1' not found in C:\xampp\htdocs\AllTest\index.php on line 27.
My questions are:
Does the use keyword always expect a class even though I tell it to import a namespace ?
How do you import a namespace (and then instantiate multiple classes in that namespace) ?
For the above example how do you use both the classes, one in main namespace and the other in namespaceproj\lib1 namespace ?

use namespaceproj\lib1 ;
Here you are importing the namespace, not all of the classes inside of that namespace. Therefore, you're trying to create a symbol lib1 pointing towards the namespace namespaceproj\lib1. This fails because you already have a lib1 symbol as a class.
use namespaceproj\lib1 as libnew;
Again, namespaceproj\lib1 is a namespace, not a class. So now you have a symbol named libnew for the namespace and you can instantiate classes using this aliased namespace:
new libnew\lib1;
PHP7 introduced group import syntax, but it still requires you to declare which classes you are importing.
use some\namespace\{ClassA, ClassB, ClassC}

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.

Are traits in PHP affected by namespaces?

From the PHP documentation:
only four types of code are affected by namespaces: classes, interfaces, functions and constants.
But, it seems to me that TRAITS are also affected:
namespace FOO;
trait fooFoo {}
namespace BAR;
class baz
{
use fooFoo; // Fatal error: Trait 'BAR\fooFoo' not found in
}
Am I wrong?
Yes, they are.
Import the trait with use outside the class for PSR-4 autoloading.
Then use the trait name inside the class.
namespace Example\Controllers;
use Example\Traits\MyTrait;
class Example {
use MyTrait;
// Do something
}
Or just use the Trait with full namespace:
namespace Example\Controllers;
class Example {
use \Example\Traits\MyTrait;
// Do something
}
I think they are affected as well. Look at some of the comments on the php.net page.
The first comment:
Note that the "use" operator for traits (inside a class) and the "use" operator for namespaces (outside the class) resolve names differently. "use" for namespaces always sees its arguments as absolute (starting at the global namespace):
<?php
namespace Foo\Bar;
use Foo\Test; // means \Foo\Test - the initial \ is optional
?>
On the other hand, "use" for traits respects the current namespace:
<?php
namespace Foo\Bar;
class SomeClass {
use Foo\Test; // means \Foo\Bar\Foo\Test
}
?>
In my experience if this piece of code you pasted resides in different files/folders and you use the spl_autoload_register function to load classes you need to do it like this:
//file is in FOO/FooFoo.php
namespace FOO;
trait fooFoo {}
//file is in BAR/baz.php
namespace BAR;
class baz
{
use \FOO\fooFoo; // note the backslash at the beginning, use must be in the class itself
}
The documentation also says "A Trait is similar to a class",
A trait is a special case of a class.
So what applied to a class also applied to a trait.

namespaces and class extends

Im trying to figure out how namespaces works in PHP, but havent really been lucky
Hope somebody could tell me what Im doing wrong here :)
code
require_once 'Vatcode.php';
$Vatcode = new \resource\Vatcode();
Vatcode.php
namespace resource;
require_once Ini::get('path/class').'/Resource.php';
class Vatcode extends Resource {
public function __construct(){
echo 'works!';
}
}
Rescource.php
namespace resource;
class Resource {
}
error
Fatal error: Class 'resource\Ini' not found in Vatcode.php
it's just a problem of namespace.
Your class Vatcode is in namesapce ressource. If, in the file of VatCode declaration you use nameofclas::... or new nameofclass() it will try to get the class in namespace ressource.
If you want to use the class Ini inside your document you have two solutions :
first give the full qualified name :
require \namespace\of\ini\Ini::get('path/class').'/Resource.php';
second using the "use" keyworld before using the get method :
use \namespace\of\ini\Ini;
require_once Ini::get('path/class').'/Resource.php';
In any case, if Ini is in "no namespace" (global namespace is the accurate word) you just has to use the solutions I gave you but only with \Ini instead of \namespace\of\ini\Ini

PHP namespaces and importation

I have a question about namespaces in PHP.
this code doesn't work :
<?php
namespace My\Functions\Printing;
class A {
public function __construct() {
echo __NAMESPACE__;
}
}
namespace My;
use My\Functions\Printing\A as A;
$obj=new namespace\A();
But this one work :
<?php
namespace My\Functions\Printing;
class A {
public function __construct() {
echo __NAMESPACE__;
}
}
namespace My;
use My\Functions\Printing\A as A;
$obj=new A();
I would like to get more information about the behavior of namespaces importation.
Why an imported class can't be accessible in the namespace where it is imported?
Probably you have a confused idea of using 'use'.
The keyword 'namespace' refers to the current namespace
namespace My\Functions\Printing;
class A {
public function __construct() {
echo __NAMESPACE__;
}
}
namespace My;
use My\Functions\Printing\A;
use My\Functions\Printing\A as myAlias;
$obj=new namespace\A(); // instance of \My\A (doesn't exist)
$obj2=new A(); // instance of \My\Functions\Printing\A
$obj3=new myAlias(); // instance of \My\Functions\Printing\A
As usual, see the documentation for complete details: php doc
I'm not sure but I think problem is in using namespace keyword.
http://www.php.net/manual/pl/language.namespaces.nsconstants.php
In first example you are in My namespace so namespace\A() == My\My\Functions\Printing\A()
My\Functions\Printing namespace look like
-- My\Functions\Printing
A
"My" namespace before importation look like:
-- My
"My" namespace after importation should look like (i thinks)
-- My
A
So why i can't acces My\A ?
I think the structure of namespace it's not changed an PHP compiler check in the "namespace imported area" before the "namespace structure".
Documentation specify namespaces look like filesystem, it's false.
If an importation of an other class is as "create a symbolic link" i must be able to acced it from the current namespace.
We can acced a symbolic link from the directory where it was created or from the absolute path but it's not possible to acced the imported class
with its new path. (\My\A)
Why ?

Categories