I'll try to describe the situation I'm having problems with:
I have one main folder. I keep all files in there (empty classes for a reason), and one sub-folder, containing the same files, with all implementations here (empty classes extend them).
the main folder's namespace is declared as Project/Folder, and the sub-folder as Project/Folder/Subfolder. These are class's declarations:
namespace Project\Folder;
class Foo extends Subfolder\Foo { }
namespace Project\Folder\Subfolder;
class Foo { }
What I want to achieve is to be able to call other classes from inside of the Project\Folder\Subfolder\Foo through these empty classes on the lower level, with only its name, e.g.:
namespace Project\Folder\Subfolder;
class Foo {
function bar() {
Another_Class::do_something();
}
}
By default, there will be called Another_Class from the Project\Folder\Subfolder namespace. I want this to refer to Another_Class from the Project\Folder namespace with the same syntax - is that possible?
I hope I explained this clear enough, if not, write a commend, and I'll try to make it clearer.
You can achieve that using the use statement.
use Project\Folder\Subfolder\Another_Class as SomeAlias;
// ...
SomeAlias::doSomething();
// or
$object = new SomeAlias();
$object->doSomething();
Alternatively, you would have to reference the entire namespace:
\Project\Folder\Subfolder\Another_Class::doSomething();
// or
$object = new \Project\Folder\Subfolder\Another_Class();
$object->doSomething();
More information here.
Related
I've got this:
use XXX\Driver\Driver;
...
var_dump(class_exists('Driver')); // false
$driver = new Driver(); // prints 123123123 since I put an echo in the constructor of this class
exit;
Well... this behaviour is quite irrational (creating objects of classes that according to PHP do not exist). Is there any way to check if a class exist under given namespace?
In order to check class you must specify it with namespace, full path:
namespace Foo;
class Bar
{
}
and
var_dump(class_exists('Bar'), class_exists('\Foo\Bar')); //false, true
-i.e. you must specify full path to class. You defined it in your namespace and not in global context.
However, if you do import the class within the namespace like you do in your sample, you can reference it via imported name and without namespace, but that does not allow you to do that within dynamic constructions and in particular, in-line strings that forms class name. For example, all following will fail:
namespace Foo;
class Bar {
public static function baz() {}
}
use Foo\Bar;
var_dump(class_exists('Bar')); //false
var_dump(method_exists('Bar', 'baz')); //false
$ref = "Bar";
$obj = new $ref(); //fatal
and so on. The issue lies within the mechanics of working for imported aliases. So when working with such constructions, you have to specify full path:
var_dump(class_exists('\Foo\Bar')); //true
var_dump(method_exists('\Foo\Bar', 'baz')); //true
$ref = 'Foo\Bar';
$obj = new $ref(); //ok
The issue (as mentioned in the class_exists() manual page user notes) is that aliases aren't taken into account whenever a class name is given as a string. This also affects other functions that take a class name, such as is_a(). Consequently, if you give the class name in a string, you must include the full namespace (e.g. '\XXX\Driver\Driver', 'XXX\\Driver\\Driver').
PHP 5.5 introduced the class constant for just this purpose:
use XXX\Driver\Driver;
...
if (class_exists(Driver::class)) {
...
}
I'm working with Magento, but this isn't a Magento specific question.
Let's say that you're working with foo.php with contains the class Foo. In Magento, /local/foo.php will be included if it exists, otherwise /core/foo.php will be included. In both, the class Foo is defined. The problem here is that both files contain the class Foo, therefore the class in /local/foo.php can't extend the class in /core/foo.php. Ultimately this requires all of the code from /core/foo.php to be copied in /local/foo.php minus my customizations.
/core/foo.php - I can't change this file!
<?php
class Foo {
public function test() {
echo 'core/foo.php :: Foo :: test';
}
}
?>
/local/foo_include.php
<?php
namespace mage {
require '../core/foo.php;
}
?>
/local/foo.php - I can't put a namespace in this file, as I have no control over the file instantiating this class.
<?php
require './foo_include.php';
use mage;
class Foo extends mage\Foo {
function __construct() {
var_dump('Un-namespaced Foo!');
}
}
$foo = new Foo();
$foo->test();
?>
The above doesn't work, saying that mage\Foo doesn't exist. (It does work if the core Foo class is defined inside foo_include instead of being brought in through an include.
Is there any way around this that I'm missing?
Normally when I see something like this, I feel like the approach isn't right and the problem needs to be examined at a higher view. That said, if this is a hack and you know it, this tweak to your hack will work. But again, I don't recommend either approach.
Change foo_include.php to this:
eval('namespace Mage {?>'.file_get_contents(__DIR__ . '/../core/foo.php').'}');
I'm unsure how Magento works, but with Symfony, the correct solution would be to override the dependency's class via parameters.
http://symfony.com/doc/current/cookbook/bundles/override.html
Is there something similar in Magento? Then you can override the class with your class, and extend the other. This still means they'd need to be in different namespaces, however the framework won't try to go to \Foo since you overrode it. Like such:
# original class for a dependency
dependency.class = \Foo
# overriden with new class
dependency.class = My\Foo
Then in your version of Foo:
class My\Foo extends \Foo {}
I read an article about namespaces in PHP. But I don't get what they are used for?
<?php
namespace MyProject {
// Regular PHP code goes here, anything goes!
function run()
{
echo 'Running from a namespace!';
}
}
I also read the PHP.net manual about it, but didn't quite get it.
I had a tough time as well, just think of it as a way to help the compiler resolve names.
So there is no ambiguity.
You could have two developers writing completely different classes but with same type identifier.
The class names could be the same. Grouping in namespaces helps the compiler/interpreter will remove the ambiguity.
So namespace Developer1.CoolClass is quite different from namespace Developer2.CoolClass
In the PHP world, namespaces are designed to solve two problems that authors of libraries and applications encounter when creating re-usable code elements such as classes or functions:
Name collisions between code you create, and internal PHP classes/functions/constants or third-party classes/functions/constants.
Ability to alias (or shorten) Extra_Long_Names designed to alleviate the first problem, improving readability of source code.
PHP Namespaces provide a way in which to group related classes, interfaces, functions and constants.
Check Here for details
Namespaces are a way to group your related classes in packages.You can assume namespaces as folders where you keep your files,in a way that both can have the files with same name but different (or same) without any ambiguity.
file1.php
<?php
namespace Foo\Bar\subnamespace;
const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
?>
file2.php
<?php
namespace Foo\Bar;
include 'file1.php';
const FOO = 2;
function foo() {}
class foo
{
static function staticmethod() {}
}
/* Unqualified name */
foo(); // resolves to function Foo\Bar\foo
foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod
echo FOO; // resolves to constant Foo\Bar\FOO
/* Qualified name */
subnamespace\foo(); // resolves to function Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // resolves to class Foo\Bar\subnamespace\foo,
// method staticmethod
echo subnamespace\FOO; // resolves to constant Foo\Bar\subnamespace\FOO
/* Fully qualified name */
\Foo\Bar\foo(); // resolves to function Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod
echo \Foo\Bar\FOO; // resolves to constant Foo\Bar\FOO
?>
Consider your write your own class, lets called it Foo. Someone else writes also a part of the project and he calls one of his classes also Foo.
Namespaces solve this problem.
Example:
Namespace MyClasses;
Class Foo
{
}
NameSpace HisClasses;
Class Foo
{
}
$myfoo = new MyClasses\Foo();
$hisfoo = new HisClasses\Foo();
Namespaces are used to isolate functions and class declarations in order to make libraries and "helpers" (files containing functions) more portable. By putting a library in a name space, you reduce the chances of your class names colliding with what an author who may want to use your library may want to call their classes For example, you can have multiple classes named "user" if they're in separate namespaces.
I ran into an issue with parent/child classes in different namespaces that I'm wondering if it's my improper use, or if this is a quirk of PHP namespaces:
<?php
namespace myVendorName;
class MyParentClass {
protected $args = array();
function factory($class) {
return new $class($this->args);
}
}
?>
<?php
namespace myVendorName\subPackage;
class foo {
}
class bar extends \myVendorName\MyParentClass {
function myFunc() {
var_dump(new foo()); // Works (we're in the same namespace)
var_dump($this->factory('foo')); // Doesn't work (no such class as myVendorName\foo)
var_dump($this->factory('subPackage\foo')); // Works
}
}
?>
The above code doesn't work as I'd expect. In the \myVendorName\subPackage\bar->myFunc() method, I'd like to get a \myVendorName\subPackage\foo class. If I just create it there, I can create it by only its class name since the namespace is the same. However, those classes in reality are more complex, and there's a factory method to create them. The factory method is universal, and is defined in the root vendor namespace. And the bar class doesn't overwrite that factory method; it simply inherits it. However, when referring to a class object by name, it seems to still operate in the parent's namespace, rather than having the method truly get inherited by the child and operate in the child's namespace.
Is there a way for a parent class method that's going to be inherited directly to use the child's namespace, or at least peek at what it is? Or does each of my child classes have to overwrite the factory method to fix the namespace, and call the parent method within themselves?
The answer, as Passerby indicated is that PHP does have a __NAMESPACE__ constant that is filled with the current namespace (though no leading slash). So modifying the factory function to:
function factory($class) {
if ($class[0] != '\\') {
$class = '\\'.__NAMESPACE__.$class; // If not a fully-qualified classname, prepend namespace
}
return new $class($args);
}
works as expected (there's an example of this in the PHP documentation)
Is there any way to temporary use a namespace ?
I'm using a library to create forms and it uses namespaces, the problem is that I usually want to create a form in the middle of a page, which is thus in the global namespace. Then if I want to call any function of this library I have to prefix everything with Namespace\
Isn't there any way in PHP to do something like this :
Blabla global namespace
strlen('test'); // 4
namespace Namespace
{
test();
}
More global PHP
And have it refer to Namespace\test ?
http://www.php.net/manual/en/language.namespaces.importing.php
<?php
namespace foo;
use My\Full\Classname as Another;
// this is the same as use My\Full\NSname as NSname
use My\Full\NSname;
// importing a global class
use ArrayObject;
$obj = new namespace\Another; // instantiates object of class foo\Another
$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // instantiates object of class ArrayObject
// without the "use ArrayObject" we would instantiate an object of class foo\ArrayObject
?>
This is about the closest you can get - there's no way to change the default namespace temporarily.
I know this is an old question, and while the accepted answer answers the question as it was asked, I feel like what the OP is really asking is "Can I use items in the global namespace from another namespace. The answer here is a clear and simple yes.
Imagine two classes (one in the global namespace, another in its own:
ClassInGlobal.php
<?php
class ClassInGlobal
{
public static function doStuff()
{
echo 'I do some stuff';
}
}
ClassInNamespace.php
<?php
namespace App\Classes;
class ClassInNamespace
{
public function callDoStuff()
{
\ClassInGlobal::doStuff();
}
}
The above executes fine. All that is required is a leading slash to specify the fully qualified global namespace. Additionally, you could add a use ClassInGlobal declaration right after the namespace declaration and omit the leading slash.
This might translate into the original question by abstracting the namespaced functions into a class Then you could modify the OP's code slightly to acheive this:
require './Namespace/Utilities.php';
Blabla global namespace
strlen('test'); // 4
\Namespace\Utilities::test();
More global PHP
Hope that helps someone coming here looking for that.