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 ?
Related
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}
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 am converting from c# to php and I'm having trouble transitioning in some places. Particularly namespaces. The problem I am having is I have to fully qualify every namespace when calling a class from another namespace. Is this normal?
<?php
namespace Lib\Things;
class TheThings
{
}
then in the other class
<?php
namespace App;
use Lib\Things;
class DoStuff
{
public function doStuff()
{
$things = new TheThings();
}
}
That doesn't work... I end up having to do
new Lib\Things\TheThings();
Or
<?php
namespace App;
use Lib\Things as T;
class DoStuff
{
public function doStuff()
{
$things = new T\TheThings();
}
}
I've also got this in my composer.json file
"psr-4": {
"App\\": "app/",
"Lib\\": "lib/"
}
Is that normal or am I doing something wrong here?
In the PHP manual the use keyword is referred to as importing or aliasing.
This means that
use Lib\Things;
and
use Lib\Things as Things;
are the same. This results that you don't have to use the fully qualified names to instantiate classes from a namespace, you can use only the alias of the imported namespace. So in your case, the following would have worked:
<?php
namespace App;
use Lib\Things;
// same as:
// use Lib\Things as Things; // explicit alias
class DoStuff
{
public function doStuff()
{
$things = new Things\TheThings();
}
}
(Note that this is the same as your second example, the only difference is that the alias is not explicitly set here to T (and defaults to Things).
To be able to use the class name without any namespace prefix, you will have to set the alias of the actual class:
<?php
namespace App;
use Lib\Things\TheThings;
// same as:
// use Lib\Things\TheThings as TheThings; // explicit alias
class DoStuff
{
public function doStuff()
{
$things = new TheThings();
}
}
In conclusion, if you start thinking about the use operator as setting an alias for a namespace or class (or other), you will get the hang of it.
PS 1:
Before PHP 7, if you wanted to import multiple classes from the same namespace, you had to write:
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;
From PHP 7.0 onwards, classes, functions and constants being imported from the same namespace can be grouped together in a single use statement:
use some\namespace\{ClassA, ClassB, ClassC as C};
PS 2:
composer helps in automagically including/loading the actual php files, based on some PSR* rule, it does not have any role in how namespaces work in bare PHP.
When you do:
$things = new TheThings();
Class is searched on the current namespace (App in your example), thats why not worked.
So, you need to specify full class namespace, so interpreter know which class are you refering, you could also have a namepsace2/TheThings and this/is/another/namespace/TheThings classes.
Just include full class namespace
use Lib\Things\TheThings;
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.
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();