PHP 8.4.1 Released!

FAQ: Dinge, die Sie über Namespaces wissen sollten

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

Diese häufig gestellten Fragen (FAQ) wurden in zwei Abschnitte aufgeteilt: allgemeine Fragen und einige Implementierungsdetails, deren vollständiges Verständnis hilfreich sein kann.

Zuerst die allgemeinen Fragen.

  1. Wenn ich keine Namespaces verwende, sollte mich das alles hier überhaupt interessieren?
  2. Wie verwende ich interne oder globale Klassen in einem Namespace?
  3. Wie verwende ich Klassen, Funktionen oder Konstanten mit Namespaces in ihrem eigenen Namespace?
  4. Wie wird ein Name wie \mein\name oder \name aufgelöst?
  5. Wie wird ein Name wie mein\name aufgelöst?
  6. Wie wird ein unqualifizierter Name wie name aufgelöst?
  7. Wie wird ein unqualifizierter Funktions- oder Konstantenname wie name aufgelöst?

Es gibt einige Implementierungsdetails von Namespaces, deren Verständnis hilfreich ist.

  1. Importierte Namen dürfen keine Konflikte mit Klassennamen in der gleichen Datei erzeugen.
  2. Verschachtelte Namespaces sind nicht erlaubt.
  3. Dynamische Namespacenamen sollten den Backslash escapen.
  4. Zugriff auf undefinierte Konstanten mit Backslashes beendet das Skript mit einem fatal error.
  5. Die speziellen Konstanten null, true und false können nicht überschrieben werden.

Wenn ich keine Namespaces verwende, sollte mich das alles hier überhaupt interessieren?

Nein. Namespaces haben keinerlei Einfluss auf bereits bestehenden Code oder irgendwelchen Code der noch geschrieben wird, der keine Namespaces verwendet. Sie können folgenden Code schreiben, wenn Sie dies wünschen:

Beispiel #1 Zugriff auf globale Klassen außerhalb eines Namespace

<?php
$a
= new \stdClass;
?>

Dies ist äquivalent zu:

Beispiel #2 Zugriff auf globale Klassen außerhalb eines Namespace

<?php
$a
= new stdClass;
?>

Wie verwende ich interne oder globale Klassen in einem Namespace?

Beispiel #3 Zugriff auf interne Klassen in Namespaces

<?php
namespace foo;
$a = new \stdClass;

function
test(\ArrayObject $parameter_type_example = null) {}

$a = \DirectoryIterator::CURRENT_AS_FILEINFO;

// erben von einer internen oder globalen Klasse
class MyException extends \Exception {}
?>

Wie verwende ich Klassen, Funktionen oder Konstanten mit Namespaces in ihrem eigenen Namespace?

Beispiel #4 Zugriff auf interne Klassen, Funktionen oder Konstanten in Namespaces

<?php
namespace foo;

class
MyClass {}

// verwendet eine Klasse des aktuellen Namensraumes als Parametertyp
function test(MyClass $parameter_type_example = null) {}
// eine andere Möglichkeit, eine Klasse des aktuellen Namensraums
// als Parametertyp zu verwenden
function test(\foo\MyClass $parameter_type_example = null) {}

// ableiten von einer Klasse aus dem aktuellen Namespace
class Extended extends MyClass {}

// Zugriff auf eine globale Funktion
$a = \globalfunc();

// Zugriff auf eine globale Konstante
$b = \INI_ALL;
?>

Wie wird ein Name wie \mein\name oder \name aufgelöst?

Namen, die mit einem \ beginnen, werden immer zu exakt dem aufgelöst wie sie aussehen. \mein\name ist also tatsächlich \mein\name und \Exception ist Exception.

Beispiel #5 Vollständig qualifizierte Namen

<?php
namespace foo;
$a = new \my\name(); // erzeugt ein Objekt der Klasse "my\name"
echo \strlen('hi'); // ruft die Funktion "strlen" auf
$a = \INI_ALL; // $a wird auf den Wert der Konstante "INI_ALL" gesetzt
?>

Wie wird ein Name wie mein\name aufgelöst?

Namen, die einen Backslash beinhalten, aber nicht mit einem Backslash beginnen, wie z. B. mein\name, können auf zwei verschiedene Arten aufgelöst werden.

Falls es einen Import-Ausdruck gibt, der einen Alias für einen anderen Namen definiert, so dass dieser mein heißen soll, dann wird dieser Alias für das mein in mein\name angewandt.

Andernfalls wird der aktuelle Namespace vor mein\name vorangestellt.

Beispiel #6 Qualifizierte Namen

<?php
namespace foo;
use
blah\blah as foo;

$a = new my\name(); // erzeugt ein Objekt der Klasse "foo\my\name"
foo\bar::name(); // ruft die statische Methode "name"
// der Klasse "blah\blah\bar" auf
my\bar(); // ruft die Funktion "foo\my\bar" auf
$a = my\BAR; // setzt $a auf den Wert der Konstante "foo\my\BAR"
?>

Wie wird ein unqualifizierter Name wie name aufgelöst?

Klassennamen, die keinen Backslash beinhalten, wie z. B. name, können auf zwei Arten aufgelöst werden.

Falls es einen Import-Ausdruck gibt, der einen Alias für einen anderen Namen definiert, so dass dieser name heißen soll, dann wird dieser Alias angewandt.

Andernfalls wird der aktuelle Namespace name vorangestellt.

Beispiel #7 Unqualifizierter Klassennamen

<?php
namespace foo;
use
blah\blah as foo;

$a = new name(); // erzeugt ein Objekt der Klasse "foo\name"
foo::name(); // ruft die statische Methode "name" der Klasse "blah\blah" auf
?>

Wie wird ein unqualifizierter Funktions- oder Konstantenname wie name aufgelöst?

Funktions- oder Konstantennamen, die keinen Backslash beinhalten, wie z. B. name, können auf zwei verschiedene Arten aufgelöst werden.

Zuerst wird der aktuelle Namespace dem name vorangestellt.

Wenn die Konstante oder Funktion name im aktuellen Namensraum nicht existiert, so wird die globale Konstante oder Funktion name verwendet, wenn sie existiert.

Beispiel #8 Unqualifizierte Funktions- oder Konstantennamen

<?php
namespace foo;
use
blah\blah as foo;

const
FOO = 1;

function
my() {}
function
foo() {}
function
sort(&$a)
{
\sort($a);
$a = array_flip($a);
return
$a;
}

my(); // ruft "foo\my" auf
$a = strlen('hi'); // ruft die globale Funktion "strlen" auf, weil
// foo\strlen nicht existiert
$arr = array(1,3,2);
$b = sort($arr); // ruft die Funktion "foo\sort" auf
$c = foo(); // ruft die Funktion "foo\foo" auf - der Alias wird ignoriert

$a = FOO; // setzt $a auf den Wert der Konstante "foo\FOO" -
// der Alias wird ignoriert
$b = INI_ALL; // setzt $b auf den Wert der globalen Konstante "INI_ALL"
?>

Importierte Namen dürfen keine Konflikte mit Klassennamen in der gleichen Datei erzeugen.

Die folgende Kombination von Skripten ist gültig:

file1.php

<?php
namespace mein\zeug;
class
MyClass {}
?>

anderes.php

<?php
namespace anderes;
class
Ding {}
?>

file2.php

<?php
namespace mein\zeug;
include
'file1.php';
include
'anderes.php';

use
anderes\Ding as MyClass;
$a = new MyClass; // erzeugt ein Objekt der Klasse "Ding"
// aus dem Namespace "anderes"
?>

Es gibt hier, trotzdem es eine Klasse MyClass im Namespace mein\zeug gibt, keinen Namenskonflikt, weil die Definition der Klasse MyClass sich in einer anderen Datei befindet. Das nächste Beispiel erzeugt hingegen einen fatal error wegen eines Namenskonflikts, weil MyClass in derselben Datei definiert wird, die auch den use-Ausdruck beinhaltet.

<?php
namespace mein\zeug;
use
anderes\Ding as MyClass;
class
MyClass {} // fatal error: Konflikt zwischen MyClass und import-Ausdruck
$a = new MyClass;
?>

Verschachtelte Namespaces sind nicht erlaubt.

PHP erlaubt das Verschachteln von Namespaces nicht.

<?php
namespace mein\zeug {
namespace
verschachtelt {
class
foo {}
}
}
?>
Es ist jedoch leicht möglich, verschachtelte Namespaces zu simulieren:
<?php
namespace mein\zeug\verschachtelt {
class
foo {}
}
?>

Dynamische Namespacenamen sollten den Backslash escapen.

Es ist wichtig zu bemerken, dass ein Backslash in Strings als Escape-Zeichen verwendet wird und daher immer verdoppelt werden sollte, wenn er in einem String verwendet wird. Andernfalls besteht das Risiko ungewollter Auswirkungen:

Beispiel #9 Gefahren von Namespacenamen in Strings mit doppelten Anführungszeichen

<?php
$a
= "gefaehrlicher\name"; // \n ist in doppelten Anführungszeichen
// ein Zeilenumbruch!
$obj = new $a;

$a = 'ueberhaupt\nicht\gefaehrlich'; // hier gibt es keine Probleme
$obj = new $a;
?>
Innerhalb eines Strings, der von einfachen Anführungszeichen umschlossen ist, ist es deutlich ungefährlicher, die Backslash-Escape-Sequenz zu verwenden. Es wird dennoch empfohlen, Backslashes in allen Strings zu escapen.

Zugriff auf undefinierte Konstanten mit Backslashes beendet das Skript mit einem fatal error.

Jeder Zugriff auf eine Konstante mit unqualifiziertem Namen, wie FOO, wird eine Notice erzeugen, welche erklärt, dass PHP angenommen hat, dass FOO der Wert der Konstante sei. Jede Konstante, qualifiziert oder vollständig qualifiziert, deren Name einen Backslash enthält, wird einen fatal error hervorrufen, wenn sie nicht gefunden wurde.

Beispiel #10 Undefinierte Konstanten

<?php
namespace bar;
$a = FOO; // notice - undefined constant "FOO" assumed "FOO";
$a = \FOO; // fatal error, undefined namespace constant FOO
$a = Bar\FOO; // fatal error, undefined namespace constant bar\Bar\FOO
$a = \Bar\FOO; // fatal error, undefined namespace constant Bar\FOO
?>

Die speziellen Konstanten null, true und false können nicht überschrieben werden.

Jeder Versuch, eine Konstante in einem Namespace zu definieren, die eine der speziellen, eingebauten Konstanten ist, wird einen fatal error hervorrufen.

Beispiel #11 Spezielle Konstanten

<?php
namespace bar;
const
NULL = 0; // fatal error;
const true = 'stupid'; // ebenfalls fatal error;
// etc.
?>

add a note

User Contributed Notes 6 notes

up
15
manolachef at gmail dot com
12 years ago
There is a way to define a namespaced constant that is a special, built-in constant, using define function and setting the third parameter case_insensitive to false:

<?php
namespace foo;
define(__NAMESPACE__ . '\NULL', 10); // defines the constant NULL in the current namespace
var_dump(NULL); // will show 10
var_dump(null); // will show NULL
?>

No need to specify the namespace in your call to define(), like it happens usually
<?php
namespace foo;
define(INI_ALL, 'bar'); // produces notice - Constant INI_ALL already defined. But:

define(__NAMESPACE__ . '\INI_ALL', 'bar'); // defines the constant INI_ALL in the current namespace
var_dump(INI_ALL); // will show string(3)"bar". Nothing unespected so far. But:

define('NULL', 10); // defines the constant NULL in the current namespace...
var_dump(NULL); // will show 10
var_dump(null); // will show NULL
?>

If the parameter case_insensitive is set to true
<?php
namespace foo;
define (__NAMESPACE__ . '\NULL', 10, true); // produces notice - Constant null already defined
?>
up
7
shaun at slickdesign dot com dot au
8 years ago
When creating classes or calling static methods from within namespaces using variables, you need to keep in mind that they require the full namespace in order for the appropriate class to be used; you CANNOT use an alias or short name, even if it is called within the same namespace. Neglecting to take this into account can cause your code to use the wrong class, throw a fatal missing class exception, or throw errors or warnings.

In these cases, you can use the magic constant __NAMESPACE__, or specify the full namespace and class name directly. The function class_exists also requires the full namespace and class name, and can be used to ensure that a fatal error won't be thrown due to missing classes.

<?php

namespace Foo;
class
Bar {
public static function
test() {
return
get_called_class();
}
}

namespace
Foo\Foo;
class
Bar extends \Foo\Bar {
}

var_dump( Bar::test() ); // string(11) "Foo\Foo\Bar"

$bar = 'Foo\Bar';
var_dump( $bar::test() ); // string(7) "Foo\Bar"

$bar = __NAMESPACE__ . '\Bar';
var_dump( $bar::test() ); // string(11) "Foo\Foo\Bar"

$bar = 'Bar';
var_dump( $bar::test() ); // FATAL ERROR: Class 'Bar' not found or Incorrect class \Bar used
up
3
teohad at NOSPAM dot gmail dot com
8 years ago
[Editor's note: that behavior is caused by a bug in PHP 7.0, which has been fixed as of PHP 7.0.7.]

Regarding the entry "Import names cannot conflict with classes defined in the same file".
- I found that since PHP 7.0 this is no longer the case.
In PHP 7.0 you can have a class with a name that matches an imported class (or namespace or both at the same time).

<?php
namespace ns1 {
class
ns1 {
public static function
write() {
echo
"ns1\\ns1::write()\n";
}
}
}

namespace
ns1\ns1 {
class
ns1c {
public static function
write() {
echo
"ns1\\ns1\\ns1c::write()\n";
}
}
}

namespace
ns2 {
use
ns1\ns1 as ns1; // both a class in ns1, and a namespace ns1\ns1

// the next class causes fatal error in php 5.6, not in 7.0
class ns1 {
public static function
write() {
echo
"ns2\\ns1::write()\n";
}
}

ns1::write(); // calls imported ns1\ns1::write()
ns1\ns1c::write(); // calls imported ns1\ns1\ns1c::write()
namespace\ns1::write(); // calls ns2\ns1::write()
}
?>
up
6
phpcoder
9 years ago
Regarding "Neither functions nor constants can be imported via the use statement." Actually you can do it in PHP 5.6+:

<?php

// importing a function (PHP 5.6+)
use function My\Full\functionName;

// aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;

// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;
?>
up
1
theking2 at king dot ma
2 years ago
Just like class names currently namespaces are not case sensitive. So no errors will be shown here:

<?php declare(strict_types=1);
namespace
Foo;
class
Bar {
public function
__construct() {
echo
'Map constructed';
}
}

$foobar = new \foo\bar();
up
-4
okaresz
11 years ago
To correct manolachef's answer: define() ALWAYS defines constants in the GLOBAL namespace.

As nl-x at bita dot nl states in the note at http://www.php.net/manual/en/function.define.php, the constant "NULL" can be defined with define() case-sensitively, but can only be retrieved with constant(), leaving the meaning of NULL uppercase keyword as the only value of the type null.
To Top