English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Tutorial di base di PHP

Tutorial avanzato di PHP

PHP & MySQL

Manuale di riferimento di PHP

Spazi di nomi PHP

Il namespace di PHP (namespace) è stato introdotto in PHP 5.3, se hai studiato C# e Java, il namespace non è una novità. Tuttavia, in PHP ha un significato abbastanza importante.

Il namespace di PHP può risolvere i seguenti due tipi di problemi:

  • Il codice scritto dall'utente e il nome in conflitto con le classi/funzioni/constanti interne di PHP o le classi/funzioni/constanti di terze parti.

  • Crea un nome alias (o breve) per un nome identificatore lungo (solitamente per mitigare il primo problema di tipo) per migliorare la leggibilità del codice sorgente.

Definisci il namespace

Per impostazione predefinita, tutti i nomi di costanti, classi e funzioni sono messi nello spazio globale, come supportato prima dell'introduzione dei namespace in PHP.

Il namespace viene dichiarato con la parola chiave namespace. Se un file contiene un namespace, deve dichiarare il namespace prima di qualsiasi altro codice. Il formato della sintassi è il seguente;

<?php  
// Definisci il codice nel namespace 'MyProject'  
namespace MyProject;  
 
// ... codice ...

Puoi anche definire codice di namespace diverso nello stesso file, come:

<?php  
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
namespace AnotherProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

Non si consiglia di utilizzare questa sintassi per definire più namespace in un singolo file. Si consiglia di utilizzare la sintassi a graffiatura riportata di seguito.

<?php
namespace MyProject {
    const CONNECT_OK = 1;
    class Connection { /* ... */ }
    function connect() { /* ... */ }
}
namespace AnotherProject {
    const CONNECT_OK = 1;
    class Connection { /* ... */ }
    function connect() { /* ... */ }
}
?>

Combina il codice non di namespace globale con il codice di namespace, può essere utilizzato solo la sintassi a graffiatura. Il codice globale deve essere racchiuso in una dichiarazione namespace senza nome e graffiature, ad esempio:

<?php
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // Codice globale
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

L'unica istruzione legittima prima della dichiarazione dello spazio dei nomi è la dichiarazione declare per definire il modo di codifica del file sorgente. Tutti i codici non PHP, inclusi gli spazi bianchi, non possono apparire prima della dichiarazione dello spazio dei nomi.

<?php
declare(encoding='UTF-8'); // Definizione di più spazi dei nomi e codice non incluso in uno spazio dei nomi
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // Codice globale
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

Il seguente codice genererà un errore di sintassi:

<html>
<?php
namespace MyProject; // Errore fatale se <html> precede lo spazio dei nomi - lo spazio dei nomi deve essere la prima istruzione del script
?>

Sottospazio dei nomi

Simile alla relazione tra directory e file, uno spazio dei nomi PHP permette di specificare nomi di spazi dei nomi gerarchici. Pertanto, i nomi degli spazi dei nomi possono essere definiti in modo gerarchico:

<?php
namespace MyProject\Sub\Level; // Dichiarazione di uno spazio dei nomi gerarchico singolo
const CONNECT_OK = 1;
class Connection { /* ... */ }
function Connect() { /* ... */ }
?>

L'esempio sopra ha creato la costante MyProject\Sub\Level\CONNECT_OK, la classe MyProject\Sub\Level\Connection e la funzione MyProject\Sub\Level\Connect.

Uso dello spazio dei nomi

Il nome della classe in uno spazio dei nomi PHP può essere richiamato in tre modi:

  • Nome non limitato, o nome di classe senza prefissoAd esempio $a=new foo(); o foo::staticmethod();. Se lo spazio dei nomi corrente è currentnamespace, foo sarà interpretato come currentnamespace\foo. Se il codice che utilizza foo è globale, non contenuto in alcun spazio dei nomi, foo sarà interpretato come foo. Attenzione: se una funzione o una costante non definita nello spazio dei nomi viene risolta come nome di funzione o costante non limitata, sarà interpretato come nome di funzione o costante globale.

  • Nome completamente qualificato, o nome che contiene un prefissoAd esempio $a = new subnamespace\foo(); o subnamespace\foo::staticmethod();. Se il namespace corrente è currentnamespace, foo viene interpretato come currentnamespace\subnamespace\foo. Se il codice che utilizza foo è globale, non incluso in alcun namespace, foo viene interpretato come subnamespace\foo.

  • Nome completamente qualificato, o nome che contiene l'operatore di prefisso globaleAd esempio, $a = new \currentnamespace\foo(); o \currentnamespace\foo::staticmethod();. In questo caso, foo viene sempre interpretato come il nome letterale (literal name) currentnamespace\foo nel codice.

Ecco un esempio che utilizza questi tre modi:

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() {}
}
/* 非限定名称 */
foo(); // 解析为函数 Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo ,方法为 staticmethod
echo FOO; // 解析为常量 Foo\Bar\FOO
/* 限定名称 */
subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo
                                  // nonché il metodo della classe staticmethod
echo subnamespace\FOO; // interpretato come costante Foo\Bar\subnamespace\FOO
                                  
/* nome completo */
\Foo\Bar\foo(); // interpretato come la funzione Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // interpretato come la classe Foo\Bar\foo, nonché il metodo della classe staticmethod
echo \Foo\Bar\FOO; // interpretato come costante Foo\Bar\FOO
?>

Attenzione, per accedere a qualsiasi classe, funzione o costante globale, è possibile utilizzare il nome completo, ad esempio \strlen() o \Exception o \INI_ALL.

accesso a classi, funzioni e costanti globali all'interno del namespace:

<?php
namespace Foo;
function strlen() {}
const INI_ALL = 3;
class Exception {}
$a = \strlen('hi'); // chiamata alla funzione globale strlen
$b = \INI_ALL; // accesso alla costante globale INI_ALL
$c = new \Exception('error'); // esempio di istanziazione della classe globale Exception
?>

Spazi dei nomi e caratteristiche linguistiche dinamiche

L'implementazione degli spazi dei nomi PHP è influenzata dalle sue caratteristiche dinamiche del linguaggio. Pertanto, se si desidera convertire il seguente codice in uno spazio dei nomi, accedere agli elementi in modo dinamico.

codice del file example1.php:

<?php
class classname
{
    function __construct()
    {
        echo __METHOD__, "\n";
    }
}
function funcname()
{
    echo __FUNCTION__, '\n';
}
const constname = "global";
$a = 'classname';
$obj = new $a; // stampa classname::__construct
$b = 'funcname';
$b(); // stampa funcname
echo constant('constname'), "\n"; // stampa globale
?>

è necessario utilizzare il nome completo (incluso il nome della classe prefisso del namespace). Attenzione che poiché nel nome della classe, della funzione o del nome costante dinamici, il nome completo e il nome qualificato non hanno differenze, il trattino obliquo iniziale non è necessario.

accesso dinamico degli elementi dello spazio dei nomi

<?php
namespace namespacename;
class classname
{
    function __construct()
    {
        echo __METHOD__, "\n";
    }
}
function funcname()
{
    echo __FUNCTION__, '\n';
}
const constname = 'namespaced';
include 'example1.php';
$a = 'classname';
$obj = new $a; // Output: classname::__construct
$b = 'funcname';
$b(); // Output: nome della funzione
echo constant('constname'), '\n'; // Output: global
/* Se si utilizzano virgolette doppie, il metodo è "\\namespacename\\classname" */
$a = '\namespacename\classname';
$obj = new $a; // Output: namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // Output: namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // Output: namespacename\funcname
$b = '\namespacename\funcname';
$b(); // Output: namespacename\funcname
echo constant('\namespacename\constname'), '\n'; // Output: namespaced
echo constant('namespacename\constname'), '\n'; // Output: namespaced
?>

Parola chiave namespace e costante __NAMESPACE__

PHP supporta due metodi astratti per accedere agli elementi interni dello spazio dei nomi corrente, la costante magica __NAMESPACE__ e la parola chiave namespace.

Il valore della costante __NAMESPACE__ è una stringa che contiene il nome dello spazio dei nomi corrente. In modo globale, non incluso in nessuno spazio dei nomi, contiene una stringa vuota.

__NAMESPACE__ esempio, codice all'interno di uno spazio dei nomi

<?php
namespace MyProject;
echo "", __NAMESPACE__, ""; // Output: "MyProject"
?>

__NAMESPACE__ esempio, codice globale

<?php
echo "", __NAMESPACE__, ""; // Output: ""
?>

La costante __NAMESPACE__ è molto utile nel creare nomi dinamicamente, ad esempio:

Utilizzare __NAMESPACE__ per creare nomi dinamicamente

<?php
namespace MyProject;
function get($classname)
{
    $a = __NAMESPACE__ . '\' . $classname;
    return new $a;
}
?>

La parola chiave namespace può essere usata per accedere esplicitamente agli elementi del namespace corrente o dei sottonamespace. È equivalente all'operatore self nei classi.

operatore namespace, codice nel namespace

<?php
namespace MyProject;
use blah\blah as mine; // vedere "Using namespaces: importing/aliasing"
blah\mine(); // chiama la funzione blah\blah\mine()
namespace\blah\mine(); // chiama la funzione MyProject\blah\mine()
namespace\func(); // chiama la funzione MyProject\func()
namespace\sub\func(); // chiama la funzione MyProject\sub\func()
namespace\cname::method(); // chiama il metodo statico "method" della classe MyProject\cname
$a = new namespace\sub\cname(); // istanzia oggetto della classe MyProject\sub\cname
$b = namespace\CONSTANT; // assegna il valore della costante MyProject\CONSTANT a $b
?>

operatore namespace, codice globale

<?php
namespace\func(); // chiama la funzione func()
namespace\sub\func(); // chiama la funzione sub\func()
namespace\cname::method(); // chiama il metodo statico "method" della classe cname
$a = new namespace\sub\cname(); // istanzia oggetto della classe sub\cname
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b
?>

使用命名空间:别名/导入

PHP 命名空间支持 有两种使用别名或导入方式:为类名称使用别名,或为命名空间名称使用别名。

在PHP中,别名是通过操作符 use 来实现的. 下面是一个使用所有可能的三种导入方式的实例:

1、使用use操作符导入/使用别名

<?php
namespace foo;
use My\Full\Classname as Another;
// 下面的实例与 use My\Full\NSname as NSname 相同
use My\Full\NSname;
// 导入一个全局类
use \ArrayObject;
$obj = new namespace\Another; // 示例化 foo\Another 对象
$obj = new Another; // 示例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 示例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则示例化一个 foo\ArrayObject 对象
?>

2、 一行中包含多个use语句

<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // 示例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
?>

导入操作是在编译执行的,但动态的类名称、函数名称或常量名称则不是。

3、导入和动态名称

<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // 示例化一个 My\Full\Classname 对象
$a = 'Another';
$obj = new $a; // 实际化一个 Another 对象
?>

另外,导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。

4、导入和完全限定名称

<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // 示例化 My\Full\Classname 类
$obj = new \Another; // 示例化 Another 类
$obj = new Another\thing; // Esempio di istanziazione della classe My\Full\Classname\thing
$obj = new \Another\thing; // Esempio di istanziazione della classe Another\thing
?>

Utilizzo del namespace: funzioni/constanti globali di riserva

In un namespace, quando PHP incontra un nome non qualificato di classe, funzione o costante, utilizza diverse strategie di risoluzione del nome. I nomi delle classi sono sempre risolti al nome nel namespace corrente. Pertanto, per accedere a classi interne o non incluse nel namespace, è necessario utilizzare il nome completo, ad esempio:

1、 Accesso a classi globali nel namespace

<?php
namespace A\B\C;
class Exception extends \Exception {}
$a = new Exception('hi'); // $a è un oggetto della classe A\B\C\Exception
$b = new \Exception('hi'); // $b è un oggetto della classe Exception
$c = new ArrayObject; // Errore fatale, impossibile trovare la classe A\B\C\ArrayObject
?>

Per le funzioni e le costanti, se non esiste tale funzione o costante nel namespace corrente, PHP ricorre alle funzioni o costanti globali.

2、 Funzioni/constanti globali di riserva nel namespace

<?php
namespace A\B\C;
const E_ERROR = 45;
function strlen($str)
{
    return \strlen($str) - 1;
}
echo E_ERROR, "\n"; // Output "45"
echo INI_ALL, "\n"; // Output "7" - Utilizzo del costante globale INI_ALL
echo strlen('hi'), "\n"; // Output "1"
if (is_array('hi')) { // Output "is not array"
    echo "is array\n";
}
    echo "is not array\n";
}
?>

Spazio globale

Se non è definito alcun namespace, tutte le definizioni di classi e funzioni sono nello spazio globale, come prima dell'introduzione del concetto di namespace in PHP. Aggiungere il prefisso \ davanti al nome indica che tale nome è uno spazio globale, anche se si trova in un altro namespace.

Utilizzo dello spazio globale delle dichiarazioni

<?php
namespace A\B\C;
/* Questa funzione è A\B\C\fopen */
function fopen() { 
     /* ... */
     $f = \fopen(...); // Chiamare la funzione globale fopen
     return $f;
} 
?>

L'ordine degli spazi dei nomi

Dopo l'introduzione degli spazi dei nomi, il punto più comune di errore dovrebbe essere l'uso delle classi, qual è il percorso di ricerca di questa classe?

<?php
namespace A;
use B\D, C\E as F;
// Chiamata di funzione
foo(); // Prima di tutto, tentare di chiamare la funzione definita nel namespace "A"
            // Tentare di chiamare di nuovo la funzione globale "foo"
\foo(); // Chiamare la funzione globale "foo" 
my\foo(); // Chiamare la funzione "foo" definita nel namespace "A\my" 
F(); // Prima di tutto, tentare di chiamare la funzione definita nel namespace "A" 
            // Tentare di chiamare di nuovo la funzione globale "F"
// Riferimento alla classe
new B(); // Creare un oggetto della classe "B" definita nel namespace "A"
            // Se non trovato, tentare di caricare automaticamente la classe "A\B"
new D(); // Creare un oggetto della classe "D" definita nel namespace "B"
            // Se non trovato, tentare di caricare automaticamente la classe "B\D"
new F(); // Creare un oggetto della classe "E" definita nel namespace "C"
            // Se non trovato, tentare di caricare automaticamente la classe "C\E"
new \B(); // Creare un oggetto della classe "B" definita nello spazio dei nomi globale
            // Se non trovato, tentare di caricare automaticamente la classe "B"
new \D(); // Creare un oggetto della classe "D" definita nello spazio dei nomi globale
            // Se non trovato, tentare di caricare automaticamente la classe "D"
new \F(); // Creare un oggetto della classe "F" definita nello spazio dei nomi globale
            // Se non trovato, tentare di caricare automaticamente la classe "F"
// Chiamare un metodo statico o una funzione di namespace in un altro namespace
B\foo(); // Chiamare la funzione "foo" nel namespace "A\B"
B::foo(); // Chiamare il metodo "foo" della classe definita nel namespace "A"
            // Se non viene trovata la classe "A\B", tentare di caricare automaticamente la classe "A\B"
D::foo(); // Utilizzando le regole di importazione, chiamare il metodo "foo" della classe definita nel namespace "B"
            // 如果类 "B\D" 未找到,则尝试自动装载类 "B\D"
\B\foo();   // 调用命名空间 "B" 中的函数 "foo" 
\B::foo();  // 调用全局空间中的类 "B" 的 "foo" 方法
            // 如果类 "B" 未找到,则尝试自动装载类 "B"
// 当前命名空间中的静态方法或函数
A\B::foo();   // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法
              // 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B"
\A\B::foo();  // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
              // 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>

名称解析遵循下列规则:

  1. 对完全限定名称的函数,类和常量的调用在编译时解析。例如      new \A\B 解析为类 A\B

  2. 所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间     A\B\C 被导入为 C,那么对 C\D\e()     的调用就会被转换为 A\B\C\D\e()

  3. 在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间     A\B 内部调用 C\D\e(),则 C\D\e()     会被转换为 A\B\C\D\e()

  4. 非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间     A\B\C 导入为C,则 new C()     被转换为 new A\B\C()

  5. 在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数      foo() 的调用是这样解析的:

    1. 在当前命名空间中查找名为 A\B\foo() 的函数

    2. 尝试查找并调用 全局(global) 空间中的函数 foo()

  6. 在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用      new C()new D\E() 的解析过程:       new C()的解析: new D\E()的解析:为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()

    1. 在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。

    2. 尝试自动装载类 A\B\D\E

    3. 在当前命名空间中查找A\B\C类。

    4. 尝试自动装载类A\B\C