- 后端
- Web框架
【免费下载链接】yii2
Yii 2: The Fast, Secure and Professional PHP Framework
本篇技术指南围绕 Yii 2 框架的「第三方代码集成」主题展开,覆盖两大场景:在 Yii 应用中引入并使用第三方类库(Composer 包、手动下载的库、PSR-4 命名空间类、include_path依赖库与显式classMap映射),以及在第三方系统(WordPress、Joomla 或其他 PHP 框架)中把 Yii 当作类库来使用,甚至实现 Yii 1 与 Yii 2 的同进程共存。读完本文,你将掌握类自动加载的底层原理(Yii::autoload()与$classMap),并能独立完成双向集成的配置与入口脚本改造。
在 Yii 应用中使用第三方类库
在 Yii 应用里使用第三方类库,核心只有一件事:确保这些库的类文件可以被正常导入或自动加载。Yii 的自动加载机制建立在 PSR-4 标准之上,同时通过路径别名(path alias)与类映射(class map)提供了更灵活的加载途径。下面按类库的发布形式分四种情况说明。
使用 Composer 包
目前绝大多数第三方类库都以 Composer 包的形式发布。安装只需两个步骤:
- 修改应用的
composer.json文件,在require段注明需要安装哪些 Composer 包; - 运行
php composer.phar install安装这些包。
安装完成后,这些包内的类库就可以通过 Composer 的自动加载器实现自动加载。但前提是应用的入口脚本包含以下两行代码:
// 安装 Composer 自动加载器 require __DIR__ . '/../vendor/autoload.php'; // 加载 Yii 的类文件 require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';从入口脚本文档可以看到,一个标准的 Yii Web 入口脚本正是这样组织的:先注册 Composer 自动加载器,再引入 Yii 类文件,然后加载应用配置并创建、运行应用实例:
<?php defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); // 注册 Composer 自动加载器 require __DIR__ . '/../vendor/autoload.php'; // 包含 Yii 类文件 require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; // 加载应用配置 $config = require __DIR__ . '/../config/web.php'; // 创建、配置、运行一个应用 (new yii\web\Application($config))->run();为什么顺序如此重要?从源码看,Yii.php 在引入BaseYii.php之后会执行spl_autoload_register(['Yii', 'autoload'], true, true),其中第三个参数prepend = true表示将 Yii 的自动加载器注册到 PHP 自动加载栈的最前面。因此,在 Composer 自动加载器已经注册的情况下,Yii 的自动加载器拥有更高的优先级,遇到yii\*命名空间的类时会由 Yii 自己负责加载(借助Yii::$classMap与@yii别名),而其他第三方命名空间的类则交给 Composer 的 PSR-4 自动加载器处理,两者互不干扰。
使用下载的类库(非 Composer 包)
如果类库没有发布为 Composer 包,可以手动安装:
- 下载发布文件,解压到
BasePath/vendor目录(BasePath指应用自身的 base path(主目录)); - 若类库自带类自动加载器,把它安装到应用的入口脚本中,推荐放在
Yii.php导入之前,这样 Yii 官方自动加载器可以获得更高的优先级(原因同上,与spl_autoload_register的prepend参数行为一致); - 若类库没有自动加载器,但命名符合 PSR-4 标准,可以直接利用 Yii 官方自动加载器,只需为每个根命名空间声明根路径别名。
例如,假设你把一个根命名空间为xyz的类库安装在vendor/foo/bar目录,可以在应用配置文件中这样配置:
[ 'aliases' => [ '@xyz' => '@vendor/foo/bar', ], ]这一机制背后的原理在 BaseYii.php 的autoload()方法中体现得淋漓尽致:
public static function autoload($className) { if (isset(static::$classMap[$className])) { $classFile = static::$classMap[$className]; if (strncmp($classFile, '@', 1) === 0) { $classFile = static::getAlias($classFile); } } elseif (strpos($className, '\\') !== false) { $classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false); if ($classFile === false || !is_file($classFile)) { return; } } else { return; } include $classFile; // 调试模式下校验类是否真的被加载,否则抛出 UnknownClassException }也就是说,对于带命名空间的类(如xyz\Foo\Bar),Yii 会先解析@xyz/Foo/Bar.php这样的衍生别名——把@xyz替换成@vendor/foo/bar的真实路径,再检查文件是否存在并include。这就是 PSR-4 类库只需声明根别名即可被 Yii 自动加载的原因。别名解析的具体规则(最长匹配、/边界字符、getAlias()不检查路径是否真实存在等)可参阅别名文档。
依赖 include_path 的类库
如果以上情形都不符合,最可能是该类库需要依赖 PHP 的include_path配置来定位类文件。此时只需参考该库的安装说明,在 PHP 配置(如php.ini或运行时set_include_path())中把对应目录加入导入路径即可。
最坏情形:使用 Yii::$classMap 显式映射
最悲催的情形是,类库需要显式导入每个类文件。此时可以使用 Yii 的类映射机制按需导入:
- 找出该库中包含哪些类;
- 在应用的入口脚本中,把这些类及各自对应的文件路径列进
Yii::$classMap数组。
举例来说:
Yii::$classMap['Class1'] = 'path/to/Class1.php'; Yii::$classMap['Class2'] = 'path/to/Class2.php';Yii::$classMap在 BaseYii.php 中被定义为公开静态属性,其数组键为不带前导反斜杠的完整类名,数组值是对应的类文件路径(也支持路径别名)。autoload()方法会首先在$classMap中查找类名,命中后直接include对应文件,因此类映射的优先级高于 PSR-4 式的别名推导。值得留意的是,classes.php 本身就是 Yii 核心类的类映射文件(由构建脚本自动生成,包含yii\base\Action、yii\base\Application等 430 行映射项),它在 Yii.php 中被加载进Yii::$classMap,你可以参考它的写法为自己的第三方类库建立映射。
在第三方系统内使用 Yii
Yii 提供了很多开箱即用的功能,有时你可能想把其中一部分能力(比如方便的yii\helpers\ArrayHelper助手类,或活动记录 Active Record 数据库操作能力)引入 WordPress、Joomla 或其他 PHP 框架开发的应用中。实现这个目标只需两步:安装 Yii,启动 Yii。
安装 Yii
若第三方系统支持 Composer 管理依赖,直接运行:
composer require yiisoft/yii2如果你的目标只是使用数据库抽象层(DB abstraction layer)或 Yii 的其他非静态资源相关功能,可以使用特殊的 Composer 包(如cebe/assetfree-yii2)来阻止 Bower 和 NPM 包的安装,从而避免引入前端 asset 依赖。关于如何通过 Composer 的replace段跳过 assets 安装,可参考安装文档中bower-asset/jquery、bower-asset/inputmask、bower-asset/punycode、bower-asset/yii2-pjax等包的替换写法。关于 Composer 安装过程中可能遇到的问题,另请参见通过 Composer 安装 Yii。
若第三方系统不使用 Composer,也可以下载 Yii 的发布包,解压到对应系统的BasePath/vendor目录内。
在第三方入口脚本中启动 Yii
之后,修改第三方应用的入口脚本,在开头位置添加 Yii 的引入代码:
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; $yiiConfig = require __DIR__ . '/../config/yii/web.php'; new yii\web\Application($yiiConfig); // 不要在这里调用 run() 方法。这段代码与典型 Yii 应用的入口脚本非常相似,唯一的不同在于:Yii 应用实例创建之后不会紧接着调用run()方法。因为run()会接管 HTTP 请求的处理流程——一旦调用,URL 规则、请求/响应处理就全部由 Yii 接管,第三方系统也就不再是系统主体了。所以集成场景下只创建应用实例(构造yii\web\Application时会完成组件注册与初始化),把 Yii 当作一个可随时调用的服务层,而请求分发仍由第三方系统负责。
与 Yii 应用一样,你可以根据第三方系统的运行环境针对性地配置 Yii 应用实例。比如,为了使用活动记录功能,需要先用第三方系统的 DB 连接信息配置 Yii 的db应用组件:
$yiiConfig = [ 'id' => 'embedded-in-third-party', 'components' => [ 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=third_party_db', 'username' => 'dbuser', 'password' => 'dbpass', ], ], ];完成上述配置后,你就可以在第三方代码中尽情使用 Yii 提供的大多数功能了——创建 AR 模型类并用它们操作数据库、使用ArrayHelper等助手类,以及在任意位置通过Yii::$app访问这个已初始化的应用实例。
配合使用 Yii 2 和 Yii 1
如果你之前使用 Yii 1,并且有正在运行的 Yii 1 应用,不必用 Yii 2 重写整个应用,也可以通过对既有系统增添 Yii 2 独占功能来增强它。下面详细描述实现过程。
Note: Yii 2 需要 PHP 5.4+ 的版本(就当前仓库而言,framework/composer.json 中的
require段已要求php: >=7.4.0,请以你实际部署的 Yii 2 版本对应的 PHP 要求为准)。你需要确保服务器以及现有应用都能满足版本要求。
在 Yii 1 应用中安装并启动 Yii 2
首先,参考前文的方法在已有应用中安装 Yii 2(Composer 安装或解压发布包均可)。之后,按下述方式修改 Yii 1 应用的入口脚本:
// 导入下面会详细说明的定制 Yii 类文件。 require __DIR__ . '/../components/Yii.php'; // Yii 2 应用的配置文件 $yii2Config = require __DIR__ . '/../config/yii2/web.php'; new yii\web\Application($yii2Config); // 不要调用 run() // Yii 1 应用的配置文件 $yii1Config = require __DIR__ . '/../config/yii1/main.php'; Yii::createWebApplication($yii1Config)->run();创建定制版 Yii 类以桥接两个框架
由于 Yii 1 和 Yii 2 都包含名为Yii的类,直接同时引入必然冲突,因此需要创建一个定制版的Yii类把两者组合起来。可以用以下代码创建(通常放在components/Yii.php):
$yii2path = '/path/to/yii2'; require $yii2path . '/BaseYii.php'; // Yii 2.x $yii1path = '/path/to/yii1'; require $yii1path . '/YiiBase.php'; // Yii 1.x class Yii extends \yii\BaseYii { // 在这里把 YiiBase (1.x) 的代码复制粘贴进来 } Yii::$classMap = include($yii2path . '/classes.php'); // 通过 Yii 1 注册 Yii 2 的类自动加载器 Yii::registerAutoloader(['Yii', 'autoload']); // 创建依赖注入容器 Yii::$container = new yii\di\Container;这段代码之所以可行,是因为 Yii 2 的核心实现全部位于yii\BaseYii这个可扩展的基类中。从 Yii.php 可以看到,官方实现正是class Yii extends \yii\BaseYii {},随后注册自动加载器、加载classes.php类映射、创建 DI 容器。集成场景下的定制类与之同构:class Yii extends \yii\BaseYii继承 Yii 2 的全部静态方法(Yii::$app、Yii::createObject()、Yii::getAlias()、Yii::t()等),同时把 Yii 1 的YiiBase中的代码(如Yii::app()、Yii::createWebApplication())复制进定制类,于是两个框架的静态 API 在同一个Yii类中共存。Yii::$classMap加载 Yii 2 的类映射(classes.php),registerAutoloader(['Yii', 'autoload'])则把 Yii 2 的autoload()方法注册为自动加载器(这正是 Yii.php 中spl_autoload_register(['Yii', 'autoload'], true, true)的等价操作),Yii::$container = new yii\di\Container初始化依赖注入容器,使Yii::createObject()可用。
大功告成后,你可以在代码的任意位置同时访问两个框架的应用实例:
echo get_class(Yii::app()); // 输出 'CWebApplication' echo get_class(Yii::$app); // 输出 'yii\web\Application'其中Yii::app()返回 Yii 1 的应用实例(来自createWebApplication()->run()的静态访问),而Yii::$app则是 Yii 2 的应用实例——两者在同一进程中各司其职,互不干扰。
集成要点速查
下表总结了四种在 Yii 中使用第三方类库的方式及其适用条件,便于快速决策:
| 类库形态 | 处理方式 | 关键操作 |
|---|---|---|
| Composer 包 | 声明依赖并安装 | 修改composer.json,运行php composer.phar install,入口脚本加载vendor/autoload.php |
| 自带自动加载器的下载库 | 手动安装 | 解压到BasePath/vendor,在入口脚本Yii.php之前注册其自动加载器 |
| PSR-4 标准库 | 声明根别名 | 在应用配置aliases中为根命名空间添加别名(如'@xyz' => '@vendor/foo/bar') |
| 依赖 include_path 或需显式导入 | 配置导入路径 / 类映射 | 调整 PHP 导入路径,或在入口脚本填充Yii::$classMap |
反向集成(把 Yii 嵌入第三方系统)的核心口诀同样是两句:安装 Yii(Composer 或手动解压到vendor),启动 Yii(在第三方入口脚本中new yii\web\Application($config)但不调用run())。而在 Yii 1 与 Yii 2 共存的场景中,关键在于通过一个继承yii\BaseYii并融合YiiBase代码的定制Yii类,配合类映射、自动加载器注册与 DI 容器初始化,让新旧两代框架在同一 PHP 进程内和谐共处。
延伸阅读
- 入口脚本:了解入口脚本的完整职责与常量定义
- 别名(Aliases):根别名、衍生别名的定义与解析规则
- 应用结构:base path、应用配置与组件
- 活动记录 Active Record:在第三方系统中使用 Yii 的数据库操作能力
- 通过 Composer 安装 Yii:Composer 安装与问题排查
- 框架核心实现:
autoload()、getAlias()、setAlias()、createObject()等关键方法的源码 - 框架入口 Yii.php:官方
Yii类的定义与自动加载器注册 - 核心类映射:Yii 核心类的 class map 示例
- 框架 composer.json:Yii 2 的 Composer 依赖声明与 PSR-4 自动加载配置
- 后端
- Web框架
【免费下载链接】yii2
Yii 2: The Fast, Secure and Professional PHP Framework
相关推荐
Yii 2 与第三方代码集成完全指南:在 Yii 中使用外部库、将 Yii 嵌入其他系统及 Yii 2/Yii 1 共存实战
Yii 2 与第三方代码集成完全指南:在 Yii 中使用外部库、将 Yii 嵌入其他系统及 Yii 2/Yii 1 共存实战 本文基于 Yii 2 官方指南的"
后端Web框架Yii 2 第三方代码集成实战:在 Yii 中使用第三方库、把 Yii 嵌入外部系统及 Yii 1/2 双版本共存
Yii 2 第三方代码集成实战:在 Yii 中使用第三方库、把 Yii 嵌入外部系统及 Yii 1/2 双版本共存 本文基于 Yii 2 官方指南的《Работ
后端Web框架Yii 2 第三方代码集成实战:在 Yii 中使用第三方库、将 Yii 嵌入既有系统与 Yii 1/2 共存
Yii 2 第三方代码集成实战:在 Yii 中使用第三方库、将 Yii 嵌入既有系统与 Yii 1/2 共存 导读 :本文基于 Yii 2 官方指南的 Trab
后端Web框架
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考