12 Php学习:魔术常量

简介: 12 Php学习:魔术常量

PHP魔术常量

PHP 向它运行的任何脚本提供了大量的预定义常量。

不过很多常量都是由不同的扩展库定义的,只有在加载了这些扩展库时才会出现,或者动态加载后,或者在编译时已经包括进去了。

有八个魔术常量它们的值随着它们在代码中的位置改变而改变。

__LINE__:当前行号,返回这个常量所在的行号。

__FILE__:当前文件的完整路径和文件名。

__DIR__:当前文件所在的目录。

__FUNCTION__:当前函数的名称。

__CLASS__:当前类的名称。

__TRAIT__:当前 trait 的名称。

__METHOD__:当前方法的名称(包括类名)。

__NAMESPACE__:当前命名空间的名称。

详细介绍和举例

当然,让我们逐个详细解释和举例这八个 PHP 魔术常量:

  1. __LINE____LINE__ 常量返回当前行号,即它所在的代码行在源文件中的行号。这对于调试和记录错误非常有用。
    示例:
echo "当前行号:" . __LINE__;
  1. 输出:
当前行号:3
  1. __FILE____FILE__ 常量返回当前文件的完整路径和文件名。它可用于获取正在执行的脚本的文件名。
    示例:
echo "当前文件:" . __FILE__;
  1. 输出:
当前文件:/path/to/your/file.php
  1. __DIR____DIR__ 常量返回当前文件所在的目录的完整路径。
    示例:
echo "当前目录:" . __DIR__;
  1. 输出:
当前目录:/path/to/your/directory
  1. __FUNCTION____FUNCTION__ 常量返回当前函数的名称。这对于记录日志和调试时非常有用。
    示例:
function myFunction() {
    echo "当前函数:" . __FUNCTION__;
}
myFunction();
  1. 输出:
当前函数:myFunction
  1. __CLASS____CLASS__ 常量返回当前类的名称。如果在类的方法中调用,它将返回该方法所属的类的名称。
    示例:
class MyClass {
    public function showClassName() {
        echo "当前类:" . __CLASS__;
    }
}
$obj = new MyClass();
$obj->showClassName();
  1. 输出:
当前类:MyClass
  1. __TRAIT____TRAIT__ 常量返回当前 trait 的名称。如果在 trait 方法中调用,它将返回该方法所属的 trait 的名称。
    示例:
trait MyTrait {
    public function showTraitName() {
        echo "当前 trait:" . __TRAIT__;
    }
}
class MyClass {
    use MyTrait;
}
$obj = new MyClass();
$obj->showTraitName();
  1. 输出:
当前 trait:MyTrait
  1. __METHOD____METHOD__ 常量返回当前方法(包括类名)的名称。在类的方法中调用时,它将返回类名和方法名的组合。
    示例:
class MyClass {
    public function showMethodName() {
        echo "当前方法:" . __METHOD__;
    }
}
$obj = new MyClass();
$obj->showMethodName();
  1. 输出:
当前方法:MyClass::showMethodName
  1. __NAMESPACE____NAMESPACE__ 常量返回当前命名空间的名称。
    示例:
namespace MyNamespace;
echo "当前命名空间:" . __NAMESPACE__;
  1. 输出:
当前命名空间:MyNamespace

这些魔术常量在不同的上下文中提供了关于当前执行环境的重要信息,可用于调试、日志记录和动态代码生成等情景。

PHP 命名空间(namespace)

PHP 命名空间(namespace)是在 PHP 5.3 中加入的,目的是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误。

PHP 命名空间可以解决以下两类问题:

  • 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
  • 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

定义命名空间

在 PHP 中,命名空间被用来解决代码命名冲突的问题,它能够将类、函数、常量等封装在命名空间中,防止不同代码库中的同名标识符之间发生冲突。让我详细解释如何定义命名空间以及提供一个示例。

定义命名空间的基本语法:

在 PHP 中,我们使用 namespace 关键字来定义命名空间。命名空间应该出现在所有非 PHP 代码之前,包括 declareuserequireinclude 语句。下面是定义命名空间的基本语法:

namespace MyNamespace;
// 这里是命名空间内的代码

在这个语法中:

  • MyNamespace 是命名空间的名称,您可以根据需要自定义命名空间的名称。

示例:

让我们看一个简单的示例来演示如何定义命名空间并使用命名空间内的类。

// 文件:MyClass.php
namespace MyNamespace;
class MyClass {
    public function sayHello() {
        echo "Hello from MyClass!";
    }
}
// 文件:index.php
require "MyClass.php"; // 引入定义了命名空间的文件
$obj = new MyNamespace\MyClass(); // 使用完整的命名空间路径实例化类
$obj->sayHello();

在这个例子中,我们通过 namespace MyNamespace; 定义了命名空间 MyNamespace,然后在另一个文件中通过 require 引入了定义了命名空间的文件,并实例化了命名空间内的类。

通过使用命名空间,我们可以有效地组织和管理 PHP 代码,避免了命名冲突,并提高了代码的可维护性和可重用性。

子命名空间

子命名空间是指在一个已经存在的父命名空间下创建的额外命名空间。子命名空间的作用类似于文件系统中的文件夹结构,可以更好地组织和管理代码。让我详细解释一下,并给出一个示例。

在 PHP 中,可以使用 namespace 关键字定义子命名空间。子命名空间的定义方式与父命名空间类似,只需在父命名空间后面加上反斜杠 \,然后跟上子命名空间的名称。下面是定义子命名空间的基本语法:

namespace ParentNamespace\SubNamespace;
// 这里是子命名空间内的代码

在这个语法中:

  • ParentNamespace 是父命名空间的名称。
  • SubNamespace 是子命名空间的名称。

示例:

让我们通过一个示例来演示如何定义和使用子命名空间。

假设我们有一个父命名空间 MyNamespace,现在我们要在这个命名空间下创建一个子命名空间 SubNamespace,并在子命名空间中定义一个类 SubClass

// 文件:MyNamespace/SubNamespace/SubClass.php
namespace MyNamespace\SubNamespace;
class SubClass {
    public function sayHello() {
        echo "Hello from SubClass!";
    }
}

现在,在另一个文件中我们可以使用这个子命名空间中的类:

// 文件:index.php
require "MyNamespace/SubNamespace/SubClass.php"; // 引入定义了子命名空间的文件
$obj = new MyNamespace\SubNamespace\SubClass(); // 使用完整的命名空间路径实例化子命名空间中的类
$obj->sayHello();

在这个示例中,我们成功地定义了子命名空间 SubNamespace,并在其中定义了一个类 SubClass。然后在另一个文件中通过引入子命名空间的文件,并使用完整的命名空间路径实例化了 SubClass 类。

子命名空间的使用可以更好地组织和管理代码,使代码结构更加清晰易懂。

使用命名空间

使用命名空间可以帮助您组织和管理 PHP 代码,避免命名冲突,并提高代码的可维护性和可重用性。下面是一些关于如何使用命名空间的基本方法:

  1. 声明命名空间

在您的 PHP 文件的最开始位置使用 namespace 关键字来声明命名空间。例如:

namespace MyNamespace;
class MyClass {
    // 类的定义
}
function myFunction() {
    // 函数的定义
}

在这个例子中,我们声明了命名空间 MyNamespace 并定义了一个类和一个函数。

  1. 引入命名空间

要在另一个文件中使用命名空间中的类或函数,可以使用 use 关键字将命名空间引入当前的作用域。例如:

use MyNamespace\MyClass;
use function MyNamespace\myFunction;
$obj = new MyClass(); // 实例化命名空间中的类
myFunction(); // 调用命名空间中的函数
  1. 完整的命名空间路径

如果不使用 use 引入命名空间,还可以通过完整的命名空间路径来访问命名空间中的类或函数。例如:

$obj = new MyNamespace\MyClass(); // 使用完整的命名空间路径实例化类
MyNamespace\myFunction(); // 使用完整的命名空间路径调用函数
  1. 命名空间的使用

如果需要在父命名空间下创建子命名空间,可以按照前面提到的方法进行定义和使用。

示例:

// 定义命名空间和类
namespace MyNamespace;
class MyClass {
    public function sayHello() {
        echo "Hello from MyNamespace!";
    }
}
// 在另一个文件中使用命名空间中的类
require "MyClass.php"; // 引入定义了命名空间的文件
use MyNamespace\MyClass;
$obj = new MyClass(); // 实例化命名空间中的类
$obj->sayHello(); // 调用类中的方法

在这个示例中,我们定义了一个命名空间 MyNamespace,在另一个文件中使用了 use 关键字引入了命名空间中的类,并成功地实例化了这个类并调用了其中的方法。

命名空间和动态语言特征

PHP 命名空间的实现受到其语言自身的动态特征的影响。因此,如果要将下面的代码转换到命名空间中,动态访问元素。

example1.php 文件代码:

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

必须使用完全限定名称(包括命名空间前缀的类名称)。注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠是不必要的。

动态访问命名空间的元素

<?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; // 输出 classname::__construct
$b = 'funcname';
$b(); // 输出函数名
echo constant('constname'), "\n"; // 输出 global
/* 如果使用双引号,使用方法为 "\\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
?>

namespace关键字和__NAMESPACE__常量

namespace 关键字和 __NAMESPACE__ 常量是 PHP 中用于处理命名空间的重要工具。下面我将详细解释它们,并通过示例来说明它们的用法。

  1. namespace 关键字:

namespace 关键字用于定义当前文件中类、函数或常量所属的命名空间。在同一个文件中,namespace 关键字必须在所有代码之前声明。

语法:

<?php
namespace MyNamespace;
class MyClass {
    // 类实现
}
function myFunction() {
    // 函数实现
}
?>
  1. __NAMESPACE__ 常量:

__NAMESPACE__ 是一个魔术常量,用于返回当前命名空间的名称。它在任何地方都可使用,即使在没有明确指定命名空间的地方也可以使用。

示例:

<?php
// 文件: MyNamespace/MyClass.php
namespace MyNamespace;
class MyClass {
    public function getNamespace() {
        return __NAMESPACE__;
    }
}
?>
<?php
// 文件: index.php
require "MyNamespace/MyClass.php";
$obj = new MyNamespace\MyClass();
echo $obj->getNamespace(); // 输出:MyNamespace
?>

在这个示例中,我们定义了一个命名空间 MyNamespace,并在类中使用了 __NAMESPACE__ 常量来获取当前命名空间的名称。然后在另一个文件中实例化该类,并输出当前命名空间的名称。

通过使用 namespace 关键字和 __NAMESPACE__ 常量,可以更好地组织和管理代码,避免命名冲突,并了解当前代码所在的命名空间。

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

PHP中使用命名空间的别名和导入功能可以帮助简化代码,提高可读性。下面我将解释如何使用命名空间的别名(Aliases)和导入(Imports)功能,并提供示例说明:

  1. 使用别名(Aliases):

在 PHP 中,您可以为一个较长或复杂的命名空间路径创建一个短的别名,以便在代码中更方便地引用这个命名空间。这里简单介绍一下如何使用别名:

语法:

use Namespace\Long\ClassName as Alias;
示例:
use MyNamespace\SubNamespace\AnotherClass as AnotherAlias;
$object = new AnotherAlias(); // 创建一个命名空间的别名对象实例
  1. 使用导入(Imports):

通过导入命名空间,您可以在当前作用域中引入多个类、函数或常量,而无需重复使用完整的命名空间路径。下面简单介绍如何使用导入:

语法:
use Namespace\ClassA;
use Namespace\ClassB;

示例:

use MyNamespace\SubNamespace\SomeClass;
use MyApp\Helpers\HelperFunctions;
$obj1 = new SomeClass(); // 直接使用导入的类
HelperFunctions::someFunction(); // 直接访问导入的函

完整示例:

<?php
// 定义命名空间及类
namespace MyNamespace\Utilities;
class Logger {
    public function log($message) {
        echo "Logging: $message";
    }
}
// 在另一个文件中导入和使用
require "Logger.php";
use MyNamespace\Utilities\Logger as MyLogger; // 为 Logger 类创建别名 MyLogger
$log = new MyLogger();
$log->log("An important message"); // 使用别名创建的实例调用方法
?>

在这个示例中,我们定义了一个命名空间 MyNamespace\Utilities,在另一个文件中通过导入并为 Logger 类创建了别名 MyLogger,然后实例化该类并调用其中的方法。

使用命名空间:后备全局函数/常量

在PHP中,可以通过命名空间的后备全局函数和常量来实现在命名空间内找不到函数或常量时,自动回退到全局命名空间中查找。这样可以确保即使在特定命名空间内没有定义某个函数或常量,程序仍能正常运行。

后备全局函数:

使用 namespace 关键字前添加反斜杠 \ 可以在命名空间中找不到函数时,自动回退到全局空间寻找该函数。

示例:
namespace MyNamespace;
function myFunction() {
    // 函数实现
}
\myFunction(); // 如果在当前命名空间找不到 myFunction,则自动回退到全局空间查找

后备全局常量:

类似地,通过在命名空间中找不到常量时,在常量名前加上反斜杠 \ 可以在全局空间中查找该常量。

示例:
namespace MyNamespace;
define("MY_CONSTANT", "Some value");
echo \MY_CONSTANT; // 如果在当前命名空间找不到 MY_CONSTANT 常量,则自动回退到全局空间查找

这样,无论是函数还是常量,当在特定命名空间内找不到时,PHP会自动在全局空间中查找。这种机制确保了代码的灵活性并简化了命名空间的使用。

全局空间

如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。

使用全局空间说明

<?php
namespace A\B\C;
/* 这个函数是 A\B\C\fopen */
function fopen() { 
     /* ... */
     $f = \fopen(...); // 调用全局的fopen函数
     return $f;
} 
?>

命名空间的顺序

自从有了命名空间之后,最容易出错的该是使用类的时候,这个类的寻找路径是什么样的了。

<?php
namespace A;
use B\D, C\E as F;
// 函数调用
foo();      // 首先尝试调用定义在命名空间"A"中的函数foo()
            // 再尝试调用全局函数 "foo"
\foo();     // 调用全局空间函数 "foo" 
my\foo();   // 调用定义在命名空间"A\my"中函数 "foo" 
F();        // 首先尝试调用定义在命名空间"A"中的函数 "F" 
            // 再尝试调用全局函数 "F"
// 类引用
new B();    // 创建命名空间 "A" 中定义的类 "B" 的一个对象
            // 如果未找到,则尝试自动装载类 "A\B"
new D();    // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
            // 如果未找到,则尝试自动装载类 "B\D"
new F();    // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
            // 如果未找到,则尝试自动装载类 "C\E"
new \B();   // 创建定义在全局空间中的类 "B" 的一个对象
            // 如果未发现,则尝试自动装载类 "B"
new \D();   // 创建定义在全局空间中的类 "D" 的一个对象
            // 如果未发现,则尝试自动装载类 "D"
new \F();   // 创建定义在全局空间中的类 "F" 的一个对象
            // 如果未发现,则尝试自动装载类 "F"
// 调用另一个命名空间中的静态方法或命名空间函数
B\foo();    // 调用命名空间 "A\B" 中函数 "foo"
B::foo();   // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
            // 如果未找到类 "A\B" ,则尝试自动装载类 "A\B"
D::foo();   // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
            // 如果类 "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"
?>

关注我,不迷路,共学习,同进步

关注我,不迷路,共学习,同进步

相关文章
|
2天前
|
前端开发 JavaScript 安全
|
2天前
|
存储 PHP 数据库
|
2天前
|
PHP 数据安全/隐私保护 开发者
|
2天前
|
存储 Serverless PHP
|
2天前
|
存储 安全 PHP
|
2天前
|
存储 PHP 索引
|
2天前
|
程序员 PHP 开发者
|
2天前
|
存储 PHP 索引