PHPのお勉強!

PHP TOP

名前空間と動的言語機能

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

PHP における名前空間の実装は、PHP 自身が動的プログラミング言語であるという性質に影響を受けています。 したがって、次の例のようなコードを名前空間を使って書き直すには

例1 要素への動的なアクセス

example1.php:

<?php
class classname
{
function
__construct()
{
echo
__METHOD__,"\n";
}
}
function
funcname()
{
echo
__FUNCTION__,"\n";
}
const
constname = "global";

$a = 'classname';
$obj = new $a; // classname::__construct と表示します
$b = 'funcname';
$b(); // funcname と表示します
echo constant('constname'), "\n"; // global と表示します
?>
完全修飾名 (クラス名に名前空間プレフィックスをつけたもの) を使う必要があります。 動的なクラス名、関数名あるいは定数名においては修飾名と完全修飾名に差はないので、 先頭のバックスラッシュはなくてもかまいません。

例2 名前空間つき要素への動的なアクセス

<?php
namespace namespacename;
class
classname
{
function
__construct()
{
echo
__METHOD__,"\n";
}
}
function
funcname()
{
echo
__FUNCTION__,"\n";
}
const
constname = "namespaced";

/* ダブルクォートを使う場合は "\\namespacename\\classname" としなければなりません */
$a = '\namespacename\classname';
$obj = new $a; // namespacename\classname::__construct と表示します
$a = 'namespacename\classname';
$obj = new $a; // これも namespacename\classname::__construct と表示します
$b = 'namespacename\funcname';
$b(); // namespacename\funcname と表示します
$b = '\namespacename\funcname';
$b(); // これも namespacename\funcname と表示します
echo constant('\namespacename\constname'), "\n"; // namespaced と表示します
echo constant('namespacename\constname'), "\n"; // これも namespaced と表示します
?>

文字列中の名前空間名のエスケープに関する注意 を読んでおくことを忘れないようにしましょう。

add a note

User Contributed Notes 8 notes

up
75
Alexander Kirk
13 years ago
When extending a class from another namespace that should instantiate a class from within the current namespace, you need to pass on the namespace.

<?php // File1.php
namespace foo;
class
A {
public function
factory() {
return new
C;
}
}
class
C {
public function
tell() {
echo
"foo";
}
}
?>

<?php // File2.php
namespace bar;
class
B extends \foo\A {}
class
C {
public function
tell() {
echo
"bar";
}
}
?>

<?php
include "File1.php";
include
"File2.php";
$b = new bar\B;
$c = $b->factory();
$c->tell(); // "foo" but you want "bar"
?>

You need to do it like this:

When extending a class from another namespace that should instantiate a class from within the current namespace, you need to pass on the namespace.

<?php // File1.php
namespace foo;
class
A {
protected
$namespace = __NAMESPACE__;
public function
factory() {
$c = $this->namespace . '\C';
return new
$c;
}
}
class
C {
public function
tell() {
echo
"foo";
}
}
?>

<?php // File2.php
namespace bar;
class
B extends \foo\A {
protected
$namespace = __NAMESPACE__;
}
class
C {
public function
tell() {
echo
"bar";
}
}
?>

<?php
include "File1.php";
include
"File2.php";
$b = new bar\B;
$c = $b->factory();
$c->tell(); // "bar"
?>

(it seems that the namespace-backslashes are stripped from the source code in the preview, maybe it works in the main view. If not: fooA was written as \foo\A and barB as bar\B)
up
11
Daan
5 years ago
Important to know is that you need to use the *fully qualified name* in a dynamic class name. Here is an example that emphasizes the difference between a dynamic class name and a normal class name.

<?php
namespace namespacename\foo;

class
classname
{
function
__construct()
{
echo
'bar';
}
}

$a = '\namespacename\foo\classname'; // Works, is fully qualified name
$b = 'namespacename\foo\classname'; // Works, is treated as it was with a prefixed "\"
$c = 'foo\classname'; // Will not work, it should be the fully qualified name

// Use dynamic class name
new $a; // bar
new $b; // bar
new $c; // [500]: / - Uncaught Error: Class 'foo\classname' not found in

// Use normal class name
new \namespacename\foo\classname; // bar
new namespacename\foo\classname; // [500]: / - Uncaught Error: Class 'namespacename\foo\namespacename\foo\classname' not found
new foo\classname; // [500]: / - Uncaught Error: Class 'namespacename\foo\foo\classname' not found
up
6
museyib dot e at gmail dot com
5 years ago
Be careful when using dynamic accessing namespaced elements. If you use double-quote backslashes will be parsed as escape character.

<?php
$a
="\namespacename\classname"; //Invalid use and Fatal error.
$a="\\namespacename\\classname"; //Valid use.
$a='\namespacename\classname'; //Valid use.
?>
up
15
guilhermeblanco at php dot net
15 years ago
Please be aware of FQCN (Full Qualified Class Name) point.
Many people will have troubles with this:

<?php

// File1.php
namespace foo;

class
Bar { ... }

function
factory($class) {
return new
$class;
}

// File2.php
$bar = \foo\factory('Bar'); // Will try to instantiate \Bar, not \foo\Bar

?>

To fix that, and also incorporate a 2 step namespace resolution, you can check for \ as first char of $class, and if not present, build manually the FQCN:

<?php

// File1.php
namespace foo;

function
factory($class) {
if (
$class[0] != '\\') {
echo
'->';
$class = '\\' . __NAMESPACE__ . '\\' . $class;
}

return new
$class();
}

// File2.php
$bar = \foo\factory('Bar'); // Will correctly instantiate \foo\Bar

$bar2 = \foo\factory('\anotherfoo\Bar'); // Wil correctly instantiate \anotherfoo\Bar

?>
up
6
akhoondi+php at gmail dot com
11 years ago
It might make it more clear if said this way:

One must note that when using a dynamic class name, function name or constant name, the "current namespace", as in http://www.php.net/manual/en/language.namespaces.basics.php is global namespace.

One situation that dynamic class names are used is in 'factory' pattern. Thus, add the desired namespace of your target class before the variable name.

namespaced.php
<?php
// namespaced.php
namespace Mypackage;
class
Foo {
public function
factory($name, $global = FALSE)
{
if (
$global)
$class = $name;
else
$class = 'Mypackage\\' . $name;
return new
$class;
}
}

class
A {
function
__construct()
{
echo
__METHOD__ . "<br />\n";
}
}
class
B {
function
__construct()
{
echo
__METHOD__ . "<br />\n";
}
}
?>

global.php
<?php
// global.php
class A {
function
__construct()
{
echo
__METHOD__;
}
}
?>

index.php
<?php
// index.php
namespace Mypackage;
include(
'namespaced.php');
include(
'global.php');

$foo = new Foo();

$a = $foo->factory('A'); // Mypackage\A::__construct
$b = $foo->factory('B'); // Mypackage\B::__construct

$a2 = $foo->factory('A',TRUE); // A::__construct
$b2 = $foo->factory('B',TRUE); // Will produce : Fatal error: Class 'B' not found in ...namespaced.php on line ...
?>
up
2
m dot mannes at gmail dot com
7 years ago
Case you are trying call a static method that's the way to go:

<?php
class myClass
{
public static function
myMethod()
{
return
"You did it!\n";
}
}

$foo = "myClass";
$bar = "myMethod";

echo
$foo::$bar(); // prints "You did it!";
?>
up
2
anisgazig at gmail dot com
3 years ago
<?php

//single or double quotes with single or double backslash in dynamic namespace class.

namespace Country_Name{
class
Mexico{
function
__construct(){
echo
__METHOD__,"<br>";
}
}

$a = 'Country_Name\Mexico';//Country_Name\Mexico::__construct
$a = "Country_Name\Mexico";
//Country_Name\Mexico::__construct
$a = '\Country_Name\Mexico';
//Country_Name\Mexico::__construct
$a = "\Country_Name\Mexico";
//Country_Name\Mexico::__construct
$a = "\\Country_Name\\Mexico";
//Country_Name\Mexico::__construct
$o = new $a;

}

/* if your namespace name or class name start with lowercase n then you should be alart about the use of single or double quotes with backslash */

namespace name_of_country{
class
Japan{
function
__construct()
{
echo
__METHOD__,"<br>";
}

}

$a = 'name_of_country\Japan';
//name_of_country\Japan::__construct
$a = "name_of_country\Japan";
//name_of_country\Japan::__construct
$a = '\name_of_country\Japan';
//name_of_country\Japan::__construct
//$a = "\name_of_country\Japan";
//Fatal error: Uncaught Error: Class ' ame_of_country\Japan' not found
//In this statement "\name_of_country\Japan" means -first letter n with "\ == new line("\n). for fix it we can use double back slash or single quotes with single backslash.
$a = "\\name_of_country\\Japan";
//name_of_country\Japan::__construct
$o = new $a;
}

namespace
Country_Name{
class
name{
function
__construct(){
echo
__METHOD__,"<br>";
}
}

$a = 'Country_Name\name';
//Country_Name\Norway::__construct
$a = "Country_Name\name";
//Country_Name\Norway::__construct
$a = '\Country_Name\name';
//Country_Name\Norway::__construct
//$a = "\Country_Name\name";
//Fatal error: Uncaught Error: Class '\Country_Name ame' not found

//In this statement "\Country_Name\name" at class name's first letter n with "\ == new line("\n). for fix it we can use double back slash or single quotes with single backslash
$a = "\\Country_Name\\name";
//Country_Name\name::__construct
$o = new $a;

}

//"\n == new line are case insensitive so "\N could not affected

?>
up
1
scott at intothewild dot ca
15 years ago
as noted by guilhermeblanco at php dot net,

<?php

// fact.php

namespace foo;

class
fact {

public function
create($class) {
return new
$class();
}
}

?>

<?php

// bar.php

namespace foo;

class
bar {
...
}

?>

<?php

// index.php

namespace foo;

include(
'fact.php');

$foofact = new fact();
$bar = $foofact->create('bar'); // attempts to create \bar
// even though foofact and
// bar reside in \foo

?>
To Top