PHP魔术常量
魔术常量是PHP中的一组特殊常量,它们在不同的上下文中会被自动替换为不同的值。与普通常量不同,魔术常量不区分大小写,但为了代码的可读性,通常使用大写形式。本教程将详细介绍PHP中所有魔术常量的用法、特性和应用场景。
PHP魔术常量概述
PHP中的魔术常量以双下划线(__)开头和结尾。它们会根据它们在代码中的位置自动获取不同的值。以下是PHP中常用的魔术常量:
- __LINE__:返回当前行号
- __FILE__:返回当前文件的完整路径和文件名
- __DIR__:返回当前文件所在的目录
- __FUNCTION__:返回当前函数的名称
- __CLASS__:返回当前类的名称(包括命名空间)
- __METHOD__:返回当前方法的名称(包括类名)
- __NAMESPACE__:返回当前命名空间的名称
- __TRAIT__:返回当前trait的名称(包括命名空间)
- __COMPILER_HALT_OFFSET__:返回编译器停止解析的位置
常用魔术常量详解
__LINE__
__LINE__
魔术常量返回它在代码中所在的行号,是一个整数。它常用于调试和日志记录。
<?php
echo "<h4>__LINE__魔术常量示例</h4>";
echo "这是第 " . __LINE__ . " 行代码<br>";
// 输出: 这是第 5 行代码
echo "这是第 " . __LINE__ . " 行代码<br>";
// 输出: 这是第 8 行代码
// 在条件语句中使用
if (true) {
echo "这个条件语句在第 " . __LINE__ . " 行<br>";
// 输出: 这个条件语句在第 12 行
}
// 在函数中使用
function debug($message) {
echo "[行号: " . __LINE__ . "] " . $message . "<br>";
}
debug("这是一条调试信息");
// 输出: [行号: 19] 这是一条调试信息
?>
__FILE__
__FILE__
魔术常量返回当前文件的完整路径和文件名,包括文件扩展名。在PHP 4.0.2及以上版本中,它返回的路径是绝对路径(在CLI模式下,总是返回绝对路径)。
<?php
echo "<h4>__FILE__魔术常量示例</h4>";
echo "当前文件的完整路径: " . __FILE__ . "<br>";
// 输出: 当前文件的完整路径: E:\myProject\php\php-magic-constants.html
// 获取文件名(不包含路径)
echo "当前文件名: " . basename(__FILE__) . "<br>";
// 输出: 当前文件名: php-magic-constants.html
// 用于包含其他文件(使用相对路径)
$includePath = dirname(__FILE__) . '/includes/functions.php';
echo "包含文件的路径: " . $includePath . "<br>";
// 输出: 包含文件的路径: E:\myProject\php\includes\functions.php
?>
__DIR__
__DIR__
魔术常量返回当前文件所在的目录的路径,不包含文件名。它相当于dirname(__FILE__)
。在PHP
5.3.0及以上版本中可用。
<?php
echo "<h4>__DIR__魔术常量示例</h4>";
echo "当前文件所在的目录: " . __DIR__ . "<br>";
// 输出: 当前文件所在的目录: E:\myProject\php
echo "与dirname(__FILE__)比较: " . dirname(__FILE__) . "<br>";
// 输出: 与dirname(__FILE__)比较: E:\myProject\php
// 包含上层目录的文件
$parentIncludePath = __DIR__ . '/../config.php';
echo "上层目录文件的路径: " . $parentIncludePath . "<br>";
// 输出: 上层目录文件的路径: E:\myProject\php\..\config.php
// 构建应用程序根路径
$appRoot = __DIR__;
echo "应用程序根路径: " . $appRoot . "<br>";
// 输出: 应用程序根路径: E:\myProject\php
?>
__FUNCTION__
__FUNCTION__
魔术常量返回当前函数的名称。在PHP 5及以上版本中,如果在类方法中使用,它只返回方法名,不包含类名。
<?php
echo "<h4>__FUNCTION__魔术常量示例</h4>";
// 在普通函数中使用
function testFunction() {
echo "当前函数名: " . __FUNCTION__ . "<br>";
}
testFunction();
// 输出: 当前函数名: testFunction
// 在递归函数中使用
function recursiveFunction($count) {
echo "在 " . __FUNCTION__ . " 中, 计数: " . $count . "<br>";
if ($count < 3) {
recursiveFunction($count + 1);
}
}
recursiveFunction(1);
// 输出:
// 在 recursiveFunction 中, 计数: 1
// 在 recursiveFunction 中, 计数: 2
// 在 recursiveFunction 中, 计数: 3
// 用于日志记录
function logAction($action) {
$logMessage = date('Y-m-d H:i:s') . " - [" . __FUNCTION__ . "]: " . $action;
echo $logMessage . "<br>";
// 在实际应用中,这里会写入日志文件
}
logAction("用户登录成功");
// 输出: 2023-04-15 14:30:25 - [logAction]: 用户登录成功
?>
__CLASS__
__CLASS__
魔术常量返回当前类的名称,包括命名空间(如果有)。在PHP 5及以上版本中可用。如果在类的外部使用,它将返回空字符串。
<?php
echo "<h4>__CLASS__魔术常量示例</h4>";
// 定义一个类
class User {
public function getClassName() {
return __CLASS__;
}
public static function getStaticClassName() {
return __CLASS__;
}
}
// 创建对象并测试
$user = new User();
echo "通过实例方法获取类名: " . $user->getClassName() . "<br>";
// 输出: 通过实例方法获取类名: User
echo "通过静态方法获取类名: " . User::getStaticClassName() . "<br>";
// 输出: 通过静态方法获取类名: User
// 测试继承
class Admin extends User {
public function getClassName() {
return __CLASS__;
}
}
$admin = new Admin();
echo "子类的类名: " . $admin->getClassName() . "<br>";
// 输出: 子类的类名: Admin
echo "子类调用父类静态方法: " . $admin->getStaticClassName() . "<br>";
// 输出: 子类调用父类静态方法: User
?>
__METHOD__
__METHOD__
魔术常量返回当前方法的名称,包括类名。在PHP 5及以上版本中可用。
<?php
echo "<h4>__METHOD__魔术常量示例</h4>";
// 定义一个类
class Calculator {
public function add($a, $b) {
echo "正在执行: " . __METHOD__ . "<br>";
return $a + $b;
}
public static function multiply($a, $b) {
echo "正在执行静态方法: " . __METHOD__ . "<br>";
return $a * $b;
}
}
// 创建对象并测试
$calculator = new Calculator();
$result = $calculator->add(5, 3);
echo "结果: " . $result . "<br>";
// 输出:
// 正在执行: Calculator::add
// 结果: 8
// 调用静态方法
$result = Calculator::multiply(5, 3);
echo "结果: " . $result . "<br>";
// 输出:
// 正在执行静态方法: Calculator::multiply
// 结果: 15
// 与__FUNCTION__比较
class TestClass {
public function testMethod() {
echo "__FUNCTION__: " . __FUNCTION__ . "<br>";
echo "__METHOD__: " . __METHOD__ . "<br>";
}
}
$test = new TestClass();
$test->testMethod();
// 输出:
// __FUNCTION__: testMethod
// __METHOD__: TestClass::testMethod
?>
__NAMESPACE__
__NAMESPACE__
魔术常量返回当前命名空间的名称。在PHP 5.3.0及以上版本中可用。如果在全局命名空间中使用,它将返回空字符串。
<?php
echo "<h4>__NAMESPACE__魔术常量示例</h4>";
// 输出当前命名空间(全局命名空间)
echo "当前命名空间: '" . __NAMESPACE__ . "'<br>";
// 输出: 当前命名空间: ''
// 定义一个命名空间
namespace App\Utils;
echo "在命名空间内: '" . __NAMESPACE__ . "'<br>";
// 输出: 在命名空间内: 'App\Utils'
// 在命名空间中定义一个类
class Helper {
public function getNamespace() {
return __NAMESPACE__;
}
public function getFullClassName() {
return __NAMESPACE__ . '\\' . __CLASS__;
}
}
// 创建对象并测试
$helper = new Helper();
echo "通过方法获取命名空间: '" . $helper->getNamespace() . "'<br>";
// 输出: 通过方法获取命名空间: 'App\Utils'
echo "完整类名: '" . $helper->getFullClassName() . "'<br>";
// 输出: 完整类名: 'App\Utils\Helper'
// 返回到全局命名空间
namespace;
echo "回到全局命名空间: '" . __NAMESPACE__ . "'<br>";
// 输出: 回到全局命名空间: ''
// 使用带命名空间的类
$utilsHelper = new App\Utils\Helper();
echo "跨命名空间访问: '" . $utilsHelper->getNamespace() . "'<br>";
// 输出: 跨命名空间访问: 'App\Utils'
?>
其他魔术常量
__TRAIT__
__TRAIT__
魔术常量返回当前trait的名称,包括命名空间。在PHP 5.4.0及以上版本中可用。
<?php
echo "<h4>__TRAIT__魔术常量示例</h4>";
// 定义一个trait
namespace App\Traits;
trait Loggable {
public function getTraitName() {
return __TRAIT__;
}
public function log($message) {
echo "[" . __TRAIT__ . "] " . $message . "<br>";
}
}
// 返回到全局命名空间
namespace;
// 定义一个使用trait的类
class LoggedClass {
// 使用trait
use App\Traits\Loggable;
}
// 创建对象并测试
$loggedObject = new LoggedClass();
echo "Trait名称: " . $loggedObject->getTraitName() . "<br>";
// 输出: Trait名称: App\Traits\Loggable
$loggedObject->log("这是一条日志消息");
// 输出: [App\Traits\Loggable] 这是一条日志消息
?>
__COMPILER_HALT_OFFSET__
__COMPILER_HALT_OFFSET__
魔术常量返回编译器停止解析的位置,即__HALT_COMPILER();
语句在文件中的偏移量。这个常量主要用于PHP的phar打包工具,普通开发中较少使用。
<?php
echo "<h4>__COMPILER_HALT_OFFSET__魔术常量示例</h4>";
// 这是一个简单的示例,演示__COMPILER_HALT_OFFSET__的用法
echo "编译器停止解析的位置: " . __COMPILER_HALT_OFFSET__ . "<br>";
// 在实际应用中,这可能被用来嵌入二进制数据
// 例如:
/*
$binaryData = file_get_contents(__FILE__, false, null, __COMPILER_HALT_OFFSET__);
echo "嵌入的二进制数据长度: " . strlen($binaryData) . "字节<br>";
*/
__HALT_COMPILER();
// 这里是编译器停止解析的位置
// 之后的任何内容都不会被PHP解析
// 在phar文件中,这里通常是二进制数据
?>
魔术常量的应用场景
调试和日志记录
魔术常量在调试和日志记录中非常有用,可以帮助开发者了解代码执行的位置和上下文。
<?php
echo "<h4>魔术常量在调试和日志记录中的应用</h4>";
// 自定义调试函数
function debug($message, $level = 'info') {
$timestamp = date('Y-m-d H:i:s');
$line = __LINE__ - 1; // 减去函数定义占用的行
$file = basename(__FILE__);
$function = __FUNCTION__;
echo "[$timestamp] [$level] [$file:$line] [$function] $message<br>";
}
// 测试调试函数
debug("这是一条调试信息");
// 输出示例: [2023-04-15 14:45:10] [info] [php-magic-constants.html:582] [debug] 这是一条调试信息
debug("出现错误", 'error');
// 输出示例: [2023-04-15 14:45:10] [error] [php-magic-constants.html:585] [debug] 出现错误
// 类中的日志记录
class Logger {
public function log($message, $level = 'info') {
$timestamp = date('Y-m-d H:i:s');
$line = __LINE__ - 1;
$file = basename(__FILE__);
$class = __CLASS__;
$method = __METHOD__;
echo "[$timestamp] [$level] [$file:$line] [$class::$method] $message<br>";
}
}
// 使用日志类
$logger = new Logger();
$logger->log("用户登录");
// 输出示例: [2023-04-15 14:45:10] [info] [php-magic-constants.html:604] [Logger::log] 用户登录
$logger->log("数据库连接失败", 'error');
// 输出示例: [2023-04-15 14:45:10] [error] [php-magic-constants.html:606] [Logger::log] 数据库连接失败
?>
自动加载和文件包含
魔术常量在实现自动加载和文件包含时非常有用,可以基于当前文件的位置构建正确的路径。
<?php
echo "<h4>魔术常量在自动加载和文件包含中的应用</h4>";
// 简单的自动加载函数
function myAutoloader($className) {
// 假设类名与文件名相同,位于classes目录下
$baseDir = __DIR__ . '/classes/';
$file = $baseDir . str_replace('\\', '/', $className) . '.php';
echo "尝试加载: $file<br>";
if (file_exists($file)) {
include_once $file;
echo "成功加载类: $className<br>";
return true;
}
echo "无法加载类: $className<br>";
return false;
}
// 注册自动加载函数
spl_autoload_register('myAutoloader');
// 包含配置文件
function loadConfig() {
$configFile = __DIR__ . '/config/config.php';
echo "尝试包含配置文件: $configFile<br>";
if (file_exists($configFile)) {
include_once $configFile;
echo "配置文件加载成功<br>";
return true;
}
echo "配置文件不存在<br>";
return false;
}
// 测试配置文件加载
loadConfig();
// 构建应用程序路径
function getAppPath($relativePath = '') {
return __DIR__ . ($relativePath ? '/' . ltrim($relativePath, '/') : '');
}
echo "应用程序根路径: " . getAppPath() . "<br>";
echo "图片目录路径: " . getAppPath('images') . "<br>";
echo "CSS文件路径: " . getAppPath('css/style.css') . "<br>";
?>
动态类和方法调用
魔术常量可以用于实现动态类和方法调用,增强代码的灵活性和可扩展性。
<?php
echo "<h4>魔术常量在动态类和方法调用中的应用</h4>";
// 基础控制器类
class BaseController {
public function render($view, $data = []) {
$controllerName = str_replace('Controller', '', __CLASS__);
echo "渲染控制器 '$controllerName' 的视图 '$view'<br>";
echo "传递的数据: " . json_encode($data) . "<br>";
// 实际应用中,这里会包含对应的视图文件
}
// 动态调用方法
public function callAction($action, $params = []) {
$method = $action . 'Action';
$controller = __CLASS__;
echo "调用控制器 '$controller' 的方法 '$method'<br>";
if (method_exists($this, $method)) {
call_user_func_array([$this, $method], $params);
return true;
}
echo "方法 '$method' 不存在<br>";
return false;
}
}
// 测试基础控制器
$baseController = new BaseController();
$baseController->render('index', ['title' => '首页']);
// 输出:
// 渲染控制器 'Base' 的视图 'index'
// 传递的数据: {"title":"首页"}
$baseController->callAction('list', [1, 'all']);
// 输出:
// 调用控制器 'BaseController' 的方法 'listAction'
// 方法 'listAction' 不存在
// 用户控制器(继承基础控制器)
class UserController extends BaseController {
public function indexAction() {
echo "执行用户控制器的indexAction方法<br>";
$this->render('user/index');
}
public function viewAction($id) {
echo "执行用户控制器的viewAction方法,ID: $id<br>";
$this->render('user/view', ['id' => $id]);
}
}
// 测试用户控制器
$userController = new UserController();
$userController->callAction('index');
// 输出:
// 调用控制器 'UserController' 的方法 'indexAction'
// 执行用户控制器的indexAction方法
// 渲染控制器 'User' 的视图 'user/index'
// 传递的数据: []
$userController->callAction('view', [123]);
// 输出:
// 调用控制器 'UserController' 的方法 'viewAction'
// 执行用户控制器的viewAction方法,ID: 123
// 渲染控制器 'User' 的视图 'user/view'
// 传递的数据: {"id":123}
?>
单例模式和工厂模式
魔术常量在实现设计模式如单例模式和工厂模式时也很有用,可以动态获取类名。
<?php
echo "<h4>魔术常量在设计模式中的应用</h4>";
// 单例模式示例
class Database {
private static $instance;
// 私有构造函数,防止外部实例化
private function __construct() {
echo "初始化数据库连接 (" . __CLASS__ . ")<br>";
// 实际应用中,这里会建立数据库连接
}
// 获取单例实例
public static function getInstance() {
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
// 执行查询
public function query($sql) {
echo "执行SQL查询: $sql<br>";
// 实际应用中,这里会执行真实的SQL查询
return true;
}
}
// 获取数据库实例
$db1 = Database::getInstance();
$db1->query("SELECT * FROM users");
$db2 = Database::getInstance();
$db2->query("SELECT * FROM products");
echo "db1 和 db2 是否是同一个实例: " . ($db1 === $db2 ? "是" : "否") . "<br>";
// 输出: db1 和 db2 是否是同一个实例: 是
// 工厂模式示例
class LoggerFactory {
// 创建日志记录器
public static function createLogger($type = 'file') {
$className = ucfirst($type) . 'Logger';
echo "尝试创建日志记录器: $className<br>";
if (class_exists($className)) {
return new $className();
}
echo "不支持的日志记录器类型: $type<br>";
return null;
}
}
// 文件日志记录器
class FileLogger {
public function log($message) {
echo "[FileLogger] " . $message . "<br>";
// 实际应用中,这里会将日志写入文件
}
}
// 数据库日志记录器
class DatabaseLogger {
public function log($message) {
echo "[DatabaseLogger] " . $message . "<br>";
// 实际应用中,这里会将日志存储到数据库
}
}
// 使用工厂创建日志记录器
$fileLogger = LoggerFactory::createLogger('file');
$fileLogger->log("这是一条文件日志");
// 输出:
// 尝试创建日志记录器: FileLogger
// [FileLogger] 这是一条文件日志
$dbLogger = LoggerFactory::createLogger('database');
$dbLogger->log("这是一条数据库日志");
// 输出:
// 尝试创建日志记录器: DatabaseLogger
// [DatabaseLogger] 这是一条数据库日志
$invalidLogger = LoggerFactory::createLogger('console');
// 输出:
// 尝试创建日志记录器: ConsoleLogger
// 不支持的日志记录器类型: console
?>
PHP魔术常量的最佳实践
- 调试和日志记录:使用
__LINE__
、__FILE__
、__FUNCTION__
等魔术常量来增强日志信息,便于追踪问题。 - 文件路径处理:使用
__DIR__
和__FILE__
来构建可靠的文件路径,避免使用相对路径带来的问题。 - 动态代码生成:利用魔术常量来实现动态类和方法调用,提高代码的灵活性和可扩展性。
- 设计模式实现:在实现单例模式、工厂模式等设计模式时,使用魔术常量获取类名,减少硬编码。
- 自动加载机制:结合魔术常量和PHP的自动加载机制,实现类的自动加载。
- 避免过度使用:虽然魔术常量很有用,但也应该避免过度使用,特别是在可以使用普通变量或参数的情况下。
- 性能考虑:魔术常量的解析会有一定的性能开销,但通常影响很小。在对性能要求极高的场景中,可以考虑缓存魔术常量的值。
- 代码可读性:确保使用魔术常量的代码易于理解和维护,添加适当的注释说明。
PHP魔术常量综合示例
<?php
// 1. 基本魔术常量使用
echo "<h4>1. 基本魔术常量使用</h4>";
echo "当前行号: " . __LINE__ . "<br>";
echo "当前文件: " . __FILE__ . "<br>";
echo "当前目录: " . __DIR__ . "<br>";
echo "当前命名空间: '" . __NAMESPACE__ . "'<br>";
// 2. 创建一个简单的调试日志系统
echo "<h4>2. 简单的调试日志系统</h4>";
// 定义日志级别
define('LOG_LEVEL_DEBUG', 1);
define('LOG_LEVEL_INFO', 2);
define('LOG_LEVEL_WARNING', 3);
define('LOG_LEVEL_ERROR', 4);
// 当前日志级别
$currentLogLevel = LOG_LEVEL_DEBUG;
// 日志函数
function logMessage($message, $level = LOG_LEVEL_INFO) {
global $currentLogLevel;
// 检查日志级别
if ($level < $currentLogLevel) {
return;
}
// 获取日志级别名称
$levelNames = [
LOG_LEVEL_DEBUG => 'DEBUG',
LOG_LEVEL_INFO => 'INFO',
LOG_LEVEL_WARNING => 'WARNING',
LOG_LEVEL_ERROR => 'ERROR'
];
$levelName = isset($levelNames[$level]) ? $levelNames[$level] : 'UNKNOWN';
// 获取调用信息
$trace = debug_backtrace();
$caller = $trace[0];
$line = $caller['line'];
$file = basename($caller['file']);
$function = isset($caller['function']) ? $caller['function'] : 'main';
// 格式化日志消息
$timestamp = date('Y-m-d H:i:s');
$logMessage = "[$timestamp] [$levelName] [$file:$line] [$function] $message";
// 输出日志
echo $logMessage . "<br>";
// 在实际应用中,这里可能会将日志写入文件或数据库
}
// 测试日志函数
logMessage("这是一条信息日志", LOG_LEVEL_INFO);
logMessage("这是一条调试日志", LOG_LEVEL_DEBUG);
logMessage("这是一条警告日志", LOG_LEVEL_WARNING);
logMessage("这是一条错误日志", LOG_LEVEL_ERROR);
// 在函数中使用日志
function processData($data) {
logMessage("开始处理数据: " . json_encode($data), LOG_LEVEL_DEBUG);
// 处理数据...
if (empty($data)) {
logMessage("数据为空", LOG_LEVEL_WARNING);
return false;
}
logMessage("数据处理完成", LOG_LEVEL_INFO);
return true;
}
// 测试带日志的函数
processData(["name" => "张三", "age" => 30]);
processData([]);
// 3. 使用魔术常量实现简单的路由系统
echo "<h4>3. 简单的路由系统</h4>";
// 路由类
class Router {
private $routes = [];
// 添加路由
public function addRoute($pattern, $controller, $action) {
logMessage("添加路由: $pattern -> $controller::$action", LOG_LEVEL_DEBUG);
$this->routes[$pattern] = [
'controller' => $controller,
'action' => $action
];
}
// 匹配路由
public function match($url) {
logMessage("尝试匹配URL: $url", LOG_LEVEL_DEBUG);
foreach ($this->routes as $pattern => $route) {
// 简单的路由匹配(实际应用中可能更复杂)
if ($pattern === $url) {
logMessage("找到匹配的路由: $pattern", LOG_LEVEL_INFO);
return $route;
}
}
logMessage("未找到匹配的路由", LOG_LEVEL_WARNING);
return null;
}
// 调度请求
public function dispatch($url) {
logMessage("调度请求: $url", LOG_LEVEL_INFO);
$route = $this->match($url);
if ($route) {
$controllerName = $route['controller'];
$actionName = $route['action'];
logMessage("实例化控制器: $controllerName", LOG_LEVEL_DEBUG);
// 检查控制器是否存在
if (class_exists($controllerName)) {
$controller = new $controllerName();
// 检查方法是否存在
if (method_exists($controller, $actionName)) {
logMessage("调用方法: $controllerName::$actionName", LOG_LEVEL_DEBUG);
$controller->$actionName();
return true;
} else {
logMessage("方法不存在: $controllerName::$actionName", LOG_LEVEL_ERROR);
}
} else {
logMessage("控制器不存在: $controllerName", LOG_LEVEL_ERROR);
}
}
logMessage("请求调度失败", LOG_LEVEL_ERROR);
return false;
}
}
// 控制器基类
class BaseController {
// 渲染视图
protected function render($view, $data = []) {
$controllerName = str_replace('Controller', '', __CLASS__);
logMessage("渲染视图: $view (控制器: $controllerName)", LOG_LEVEL_DEBUG);
echo "<div class='view'>";
echo "<h3>视图: $view</h3>";
echo "<p>控制器: $controllerName</p>";
if (!empty($data)) {
echo "<p>数据: " . json_encode($data) . "</p>";
}
echo "</div>";
}
}
// 首页控制器
class HomeController extends BaseController {
public function index() {
logMessage("执行首页控制器的index方法", LOG_LEVEL_INFO);
$this->render('home/index', ["title" => "网站首页"]);
}
public function about() {
logMessage("执行首页控制器的about方法", LOG_LEVEL_INFO);
$this->render('home/about', ["title" => "关于我们"]);
}
}
// 用户控制器
class UserController extends BaseController {
public function list() {
logMessage("执行用户控制器的list方法", LOG_LEVEL_INFO);
$this->render('user/list', ["title" => "用户列表"]);
}
public function view() {
logMessage("执行用户控制器的view方法", LOG_LEVEL_INFO);
$this->render('user/view', ["title" => "查看用户", "id" => 123]);
}
}
// 创建路由实例并添加路由
$router = new Router();
$router->addRoute('/', 'HomeController', 'index');
$router->addRoute('/about', 'HomeController', 'about');
$router->addRoute('/users', 'UserController', 'list');
$router->addRoute('/users/view', 'UserController', 'view');
// 测试路由调度
/*
echo "<h5>测试路由: /</h5>";
$router->dispatch('/');
echo "<h5>测试路由: /about</h5>";
$router->dispatch('/about');
echo "<h5>测试路由: /users</h5>";
$router->dispatch('/users');
echo "<h5>测试路由: /unknown</h5>";
$router->dispatch('/unknown');
*/
// 4. 使用魔术常量实现一个简单的依赖注入容器
echo "<h4>4. 简单的依赖注入容器</h4>";
// 依赖注入容器
class Container {
private $instances = [];
private $bindings = [];
// 绑定一个类型到容器
public function bind($key, $resolver) {
logMessage("绑定类型到容器: $key", LOG_LEVEL_DEBUG);
$this->bindings[$key] = $resolver;
}
// 从容器中获取一个实例
public function make($key) {
logMessage("从容器中获取实例: $key", LOG_LEVEL_DEBUG);
// 检查实例是否已经存在
if (isset($this->instances[$key])) {
logMessage("返回缓存的实例: $key", LOG_LEVEL_DEBUG);
return $this->instances[$key];
}
// 检查是否有绑定
if (isset($this->bindings[$key])) {
$resolver = $this->bindings[$key];
logMessage("使用解析器创建实例: $key", LOG_LEVEL_DEBUG);
// 创建实例
$instance = $resolver($this);
// 缓存实例
$this->instances[$key] = $instance;
return $instance;
}
// 尝试直接实例化
if (class_exists($key)) {
logMessage("直接实例化类: $key", LOG_LEVEL_DEBUG);
// 创建实例
$instance = new $key();
// 缓存实例
$this->instances[$key] = $instance;
return $instance;
}
logMessage("无法解析: $key", LOG_LEVEL_ERROR);
return null;
}
}
// 数据库连接类
class DatabaseConnection {
private $config;
public function __construct() {
$this->config = [
'host' => 'localhost',
'port' => 3306,
'database' => 'test',
'username' => 'root',
'password' => ''
];
logMessage("初始化数据库连接", LOG_LEVEL_INFO);
}
public function connect() {
logMessage("建立数据库连接: " . $this->config['host'] . ":" . $this->config['port'], LOG_LEVEL_DEBUG);
// 实际应用中,这里会建立真实的数据库连接
return true;
}
public function query($sql) {
logMessage("执行SQL: $sql", LOG_LEVEL_DEBUG);
// 实际应用中,这里会执行真实的SQL查询
return ["success" => true, "data" => []];
}
}
// 用户服务类
class UserService {
private $db;
public function __construct(DatabaseConnection $db) {
$this->db = $db;
logMessage("初始化用户服务", LOG_LEVEL_INFO);
}
public function getUsers() {
logMessage("获取用户列表", LOG_LEVEL_INFO);
$result = $this->db->query("SELECT * FROM users");
// 实际应用中,这里会处理查询结果
return ["users" => ["张三", "李四", "王五"]];
}
}
// 创建容器实例
$container = new Container();
// 绑定服务到容器
$container->bind('DatabaseConnection', function($c) {
$db = new DatabaseConnection();
$db->connect();
return $db;
});
$container->bind('UserService', function($c) {
$db = $c->make('DatabaseConnection');
return new UserService($db);
});
// 从容器中获取服务
$userService = $container->make('UserService');
$users = $userService->getUsers();
echo "获取的用户列表: " . json_encode($users) . "<br>";
// 验证单例模式
$userService2 = $container->make('UserService');
echo "userService 和 userService2 是否是同一个实例: " . ($userService === $userService2 ? "是" : "否") . "<br>";
// 5. 使用魔术常量实现一个简单的事件系统
echo "<h4>5. 简单的事件系统</h4>";
// 事件管理器
class EventManager {
private $listeners = [];
// 注册事件监听器
public function on($event, callable $listener) {
logMessage("注册事件监听器: $event", LOG_LEVEL_DEBUG);
if (!isset($this->listeners[$event])) {
$this->listeners[$event] = [];
}
$this->listeners[$event][] = $listener;
}
// 触发事件
public function trigger($event, $data = null) {
logMessage("触发事件: $event", LOG_LEVEL_INFO);
if (!isset($this->listeners[$event])) {
logMessage("没有监听器监听事件: $event", LOG_LEVEL_DEBUG);
return;
}
// 调用所有监听器
foreach ($this->listeners[$event] as $index => $listener) {
logMessage("调用事件监听器 #$index for $event", LOG_LEVEL_DEBUG);
$listener($data);
}
}
}
// 创建事件管理器实例
$eventManager = new EventManager();
// 注册事件监听器
$eventManager->on('user_registered', function($user) {
logMessage("用户注册事件处理 - 发送欢迎邮件", LOG_LEVEL_INFO);
// 实际应用中,这里会发送欢迎邮件
echo "已向用户 '" . ($user['email'] ?? 'unknown') . "' 发送欢迎邮件<br>";
});
$eventManager->on('user_registered', function($user) {
logMessage("用户注册事件处理 - 添加到统计", LOG_LEVEL_INFO);
// 实际应用中,这里会更新统计数据
echo "已将用户 '" . ($user['name'] ?? 'unknown') . "' 添加到统计系统<br>";
});
$eventManager->on('user_logged_in', function($user) {
logMessage("用户登录事件处理 - 更新最后登录时间", LOG_LEVEL_INFO);
// 实际应用中,这里会更新用户的最后登录时间
echo "已更新用户 '" . ($user['name'] ?? 'unknown') . "' 的最后登录时间<br>";
});
// 触发事件
echo "<h5>触发用户注册事件</h5>";
$eventManager->trigger('user_registered', ["name" => "张三", "email" => "zhangsan@example.com"]);
echo "<h5>触发用户登录事件</h5>";
$eventManager->trigger('user_logged_in', ["name" => "张三", "id" => 123]);
echo "<h5>触发未注册的事件</h5>";
$eventManager->trigger('user_logged_out');
?>