
后端【免费下载链接】YOURLS The standard, self hosted, powerful and customizable, URL shortener in PHP项目地址https://gitcode.com/gh_mirrors/yo/YOURLS点击查看免费下载导读YOURLS 作为自托管的 PHP 短链接服务其数据库访问层建立在 Aura.Sql 之上仓库 composer.json 声明了对aura/sql的依赖而 includes/Database/YDB.php 直接继承自Aura\Sql\ExtendedPdo。本文以 includes/vendor/aura/sql/README.md 为主线系统讲解 Aura.Sql 在原生 PDO 基础上新增的懒连接、装饰器、数组引号、perform()方法、fetch*()/yield*()方法族、默认异常模式、查询 Profiler 与连接定位器并结合 YOURLS 的源码实现说明这些能力如何被实际落地。读完本文你将理解 YOURLS 每一条 SQL 背后的调用链并掌握在自有 PHP 项目中复用 Aura.Sql 增强能力的完整方法。Aura.Sql 是什么对原生 PDO 的零侵入扩展Aura.Sql 的核心定位是原生 PDO 的扩展层同时附带一个查询 Profiler 和一个连接定位器Connection Locator。由于ExtendedPdo直接继承自原生PDO任何已经使用原生 PDO 的代码或者类型约束为原生 PDO 的代码都可以直接换成ExtendedPdo而无需任何改动——这是其零侵入特性的根本保证从源码结构看AbstractExtendedPdo.php 声明为abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface即整个能力家族都建立在 PDO 继承体系之上。相比原生 PDOAura.Sql 新增的功能可以归纳为以下九项下文将逐一展开懒连接Lazy connection——只有真正发起需要连接的调用时才建立数据库连接装饰Decoration——DecoratedPdo可以在运行时为已有 PDO 实例附魔扩展行为数组引号Array quoting——quote()接受数组输入返回逗号分隔的引用值串新增perform()方法——执行与绑值一次完成且支持数组占位符用于IN (...)新增fetch*()方法族——常见抓取动作一站式封装新增yield*()方法族——以生成器方式逐行产出结果默认异常模式——默认启用ERRMODE_EXCEPTION而非 PDO 的ERRMODE_SILENTProfiler——可选查询分析器可对接任何 PSR-3 日志接口连接定位器——懒加载的服务定位器用于区分 default / read / write 连接。安装与依赖Composer 与 PHP 8.1Aura.Sql 通过 Composer 安装并以 PSR-4 自动加载包名为aura/sql也可以下载发行版或克隆仓库后将Aura\Sql\命名空间映射到包内的src/目录README。依赖要求该包要求 PHP 8.1 及以上官方在 PHP 8.1–8.2 上做过测试并建议尽量使用最新的 PHP 版本。Aura 系列库可能依赖外部接口但从不依赖外部实现——这使其可以在不牺牲灵活性的前提下遵循社区标准。在 YOURLS 仓库中该依赖由根目录 composer.json 的aura/sql: ^6.0锁定。从源码结构看包内src/目录的组织完全符合 PSR-4AbstractExtendedPdo、ExtendedPdo、DecoratedPdo、ConnectionLocator等核心类位于Aura\Sql\命名空间下Parser与Profiler则分别作为子命名空间组织见 src 目录结构。核心能力一懒连接与连接生命周期原生PDO在构造时就会立即连接数据库ExtendedPdo则相反只有在调用需要连接的方法时才真正建立连接。这意味着你可以创建一个实例如果从不执行任何查询就不会产生连接开销。其实现集中在 ExtendedPdo.php 的构造函数与lazyConnect()构造函数接收dsn、username、password、options、queries连接后要执行的 SQL、profiler六类参数构造函数不建立连接只把参数存入内部$args数组留待后续使用若options未指定PDO::ATTR_ERRMODE自动补上PDO::ERRMODE_EXCEPTION从 DSN 前缀推断驱动如mysql:据此选择解析器并设置标识符引用规则通过两个特殊选项控制行为CONNECT_IMMEDIATELYauraSqlImmediate置为true时立即连接DRIVER_SPECIFICauraSqlDriverSpecific置为true时使用驱动特定的构造路径PHP 8.4 使用PDO::connect()静态方法旧版本回退new PDO(...)。lazyConnect()ExtendedPdo.php在$this-pdo为空时执行真实连接并在连接建立后依次执行构造时传入的$queries——例如可以用它设置SET NAMES utf8mb4或PRAGMA等连接级初始化语句。disconnect()将内部$pdo置空允许后续再次懒连接。值得一提的安全细节ExtendedPdo::__debugInfo()ExtendedPdo.php在调试信息输出时用****遮蔽用户名与密码避免堆栈跟踪或 var_dump 泄露敏感凭据。核心能力二DecoratedPdo——运行时为既有 PDO 附魔DecoratedPdo的用途是装饰一个已经存在的 PDO 实例让既有连接在运行时获得ExtendedPdo的全部扩展行为而无须重新连接。其实现要点DecoratedPdo.php构造函数直接接收一个现成的PDO实例并保存为内部连接通过$pdo-getAttribute(PDO::ATTR_DRIVER_NAME)推断驱动从而选定解析器与标识符引用规则lazyConnect()为空操作因为已经连接disconnect()被明确禁止调用即抛出Exception\CannotDisconnect源码因为装饰器不应接管外部 PDO 实例的连接生命周期。核心能力三数组引号——quote()直接处理数组原生PDO::quote()只能接收标量ExtendedPdo::quote()的签名扩展为string|int|array|float|null当传入数组时会对数组中每个值分别调用底层quote()再以逗号连接成一个字符串AbstractExtendedPdo.php。这在手工拼接IN (...)列表时非常实用$ids [1, 2, 3]; $in $pdo-quote($ids); // 生成 1, 2, 3 $sql SELECT * FROM log WHERE id IN ($in);核心能力四perform()与智能参数绑定perform($statement, $values)是 Aura.Sql 最具代表性的方法它像query()一样执行查询但把值绑定到预处理语句作为调用的一部分AbstractExtendedPdo.php。其内部链路为lazyConnect()确保连接就绪调用prepareWithValues()完成重建 SQL 准备语句 绑定值执行execute()将语句与绑定值交给 Profiler 记录。数组占位符是perform()的杀手锏当绑定值本身是数组时占位符会被替换为逗号分隔的引用值列表从而可以直接写出WHERE id IN (:ids)并传入数组。整个重建逻辑由解析器完成见下文驱动级解析器一节。prepareWithValues()AbstractExtendedPdo.php还有两个细节若传入值为空数组直接走普通prepare()避免无谓开销只绑定语句中真实存在的占位符从而规避 PDO 的绑定值多于占位符错误绑定前由解析器rebuild()重建语句与值注意这里克隆了解析器保证每次重建状态独立。类型推断绑定bindValue()AbstractExtendedPdo.php根据 PHP 值类型自动选择 PDO 参数类型——int→PARAM_INTbool→PARAM_BOOLnull→PARAM_NULL其余标量走默认字符串类型若值是非标量数组、对象、资源则抛出Exception\CannotBindValue从异常消息中可以看到具体类型与占位符名。核心能力五fetch*()方法族——把准备→绑定→执行→抓取缩成一行原生 PDO 中抓取数据需要 prepare / bind / execute / fetch 四步fetch*()方法族把它们压缩为一次调用。所有方法签名统一为($statement, array $values [])内部全部经由perform()执行AbstractExtendedPdo.php方法返回值语义fetchAll()全部行行内为关联数组fetchAssoc()以每行第一列为键的关联数组重复键后行覆盖前行fetchCol()第一列的值组成顺序数组fetchGroup()按第一列分组$style默认PDO::FETCH_COLUMN抓多列时传PDO::FETCH_NAMEDfetchObject()单行对象默认stdClass可指定类名与构造参数fetchObjects()多行对象FETCH_CLASSfetchOne()单行关联数组无行返回falsefetchPairs()第一列为键、第二列为值的键值对数组fetchValue()首行首列的单值fetchAffected()执行写语句并返回受影响行数rowCount()源码注释特别提示了fetchObject()/fetchObjects()的一个 PDO 行为陷阱PDO 会在调用构造函数之前注入属性值因此如果类在构造函数中初始化默认属性值会覆盖注入的列值。核心能力六yield*()方法族——生成器按需取行yield*()系列是fetch*()的生成器对应物它们逐行yield而不是一次性return适合处理大结果集降低内存峰值。提供的五个方法AbstractExtendedPdo.phpyieldAll()逐行产出关联数组yieldAssoc()以第一列为键逐行产出yieldCol()逐行产出第一列yieldObjects()逐行产出对象支持类名与构造参数yieldPairs()逐行产出键值对。典型用法foreach ($pdo-yieldAll(SELECT * FROM log, []) as $row) { // 处理单行内存恒定 }核心能力七默认异常模式原生 PDO 默认的ERRMODE_SILENT让错误静默发生容易漏报ExtendedPdo默认以ERRMODE_EXCEPTION启动。这一行为在构造函数中硬编码ExtendedPdo.php只要options里没有显式设置PDO::ATTR_ERRMODE就强制补为PDO::ERRMODE_EXCEPTION。对 YOURLS 这类追求快速失败与可观测性的应用而言这保证了数据库错误会以异常形式立即暴露。核心能力八查询 Profiler——PSR-3 日志与内存记录器Aura.Sql 提供可选查询分析器用于记录每条 SQL 的执行耗时与上下文。核心类 Profiler.php 实现了ProfilerInterface日志对接构造函数接受任意 PSR-3LoggerInterface未指定时回退到内置的MemoryLoggerMemoryLogger.php——它把消息存入数组可通过getMessages()取回开关与级别setActive(bool)控制是否记录setLogLevel()默认使用LogLevel::DEBUG消息格式默认格式为{function} ({duration} seconds): {statement} {backtrace}可通过setLogFormat()自定义记录时机start($function)记录函数名与microtime(true)起点finish()计算耗时、附加 SQL 语句、绑定值print_r输出与异常堆栈回溯然后写入日志。在 YOURLS 中这一机制被深度定制见下文YOURLS 中的落地实现。核心能力九ConnectionLocator——read/write 连接路由ConnectionLocator是一个懒加载的服务定位器用于管理多个ExtendedPdo连接一个 default 连接 任意数量的 read 连接 任意数量的 write 连接ConnectionLocator.php 构造函数接收三类工厂回调。其行为规则对应 getConnection()getDefault()调用 default 工厂首次调用后缓存实例未设置则抛Exception\ConnectionNotFoundgetRead($name)未指定名称时从 read 池中随机挑一个read 池为空时回退到 default 连接getWrite($name)规则与 read 相同工厂采用懒实例化注册的是回调只有首次被请求时才真正执行并缓存为ExtendedPdo实例。这为读写分离提供了天然的接入点把只读查询路由到若干从库把写操作路由到主库全部以回调方式惰性创建连接。驱动级解析器占位符重建与标识符引用perform()之所以能处理数组占位符、重复命名占位符依赖Parser层的语句重建机制。基类 AbstractParser.php 的rebuild()核心逻辑匹配 PDO 的 0 索引数组行为若绑定值数组以键0开头先array_unshift(null)保证编号占位符从 1 对齐L100-L103分区解析先用正则把语句拆成普通文本与字符串字面量单/双引号字符串字面量部分跳过不做占位符替换避免误伤编号占位符?从 1 开始计数缺失时抛MissingParameter若对应值是数组展开为:__1, :__2, ...多个命名占位符prepareNumberedPlaceholder()命名占位符:name同名占位符多次出现时自动重命名为name__1等以避免重复绑定冲突getPlaceholderName()对应值为数组时展开为:name_0, :name_1, ...expandNamedPlaceholder()展开后的占位符与值写入final_values最终返回重建后的语句 重建后的绑定值二元组。不同驱动有各自的解析器MysqlParser在基类基础上额外识别反引号引用的标识符MysqlParser.php避免把反引号内的内容误当占位符。包内还提供PgsqlParser、SqliteParser、SqlsrvParser与NullParser见 Parser 目录ExtendedPdo构造时按 DSN 前缀选择未知驱动回退到SqliteParserAbstractExtendedPdo.php。与解析器配套的是标识符引用quoteName()支持对table.column这类多点标识符逐段引用setQuoteName()按驱动切换规则——MySQL 使用反引号转义 SQL Server 使用方括号[]其余驱动默认双引号转义——见 AbstractExtendedPdo.php。YOURLS 中的落地实现YDB 与定制 ProfilerAura.Sql 不是躺在 vendor 里的死代码它构成了 YOURLS 数据库层的骨架。1. YDB 继承 ExtendedPdoincludes/Database/YDB.php 声明class YDB extends ExtendedPdo。其init()流程依次执行connect_to_DB()真实连接失败时通过dead_or_error()优雅报错、set_emulate_state()探测PDO::ATTR_EMULATE_PREPARES支持情况不支持的 PHP/MySQL 组合回退false、start_profiler()。2. 定制 Profilerstart_profiler()YDB.php实例化 YOURLS 自定义的 Logger.php基于Aura\Sql\Profiler\MemoryLogger与 Profiler.php继承Aura\Sql\Profiler\Profiler并调整finish()再通过setProfiler()注入并把日志级别设为query——这样 Aura.Sql 触发的内部记录与yourls_debug_log()的调试日志可以区分。get_queries()/get_num_queries()YDB.php正是从 Profiler 的内存日志中过滤出SQL 前缀消息统计本次请求执行过的 SQL。3. 插件可拦截的抓取包装YDB 重写了全部fetch*()与perform()统一走fetch_wrapper()YDB.php先触发shunt_fetch_wrapper过滤器允许插件短路整个查询再通过fetch_wrapper_statement过滤器改写 SQL 语句without_filters()YDB.php可在回调期间临时禁用过滤器避免插件递归触发自身。4. 真实调用示例短链接核心逻辑大量使用扩展方法例如 includes/functions-shorturls.php 用$ydb-fetchValue()取旧 URL、用fetchAffected()执行 DELETE / INSERT / UPDATE如 L273、L303用$ydb-fetchObject()取单条短链信息L543includes/functions-install.php 用perform()建表并用fetchAffected(SHOW TABLES LIKE ...)校验includes/functions-upgrade.php 用fetchObjects()批量升级数据结构。这些写法共同体现了一行调用替代四步 PDO 操作的实际收益。质量与测试Aura.Sql 遵循语义化版本控制目标兼容 PSR-1、PSR-2 与 PSR-4 编码规范README。在包根目录执行composer install后运行./vendor/bin/phpunit即可跑单元测试。对 YOURLS 而言aura/sql以^6.0版本约束锁定因此上述 API 行为以仓库内 includes/vendor/aura/sql 的实际源码为准。小结从quote()的数组支持到perform()的智能绑值从fetch*()/yield*()的取数简写到 Profiler 与 ConnectionLocator 的可观测性与路由能力Aura.Sql 把 PHP 数据访问从PDO 样板代码提升为声明式的一行调用。在 YOURLS 中这些能力经由 YDB 与定制 Profiler 演化为可插拔、可观测的数据库层——理解这条链路无论对于排查 YOURLS 的 SQL 问题还是在自己的 PHP 8.1 项目中复用这套模式都极具实战价值。赞分享后端【免费下载链接】YOURLS The standard, self hosted, powerful and customizable, URL shortener in PHP项目地址https://gitcode.com/gh_mirrors/yo/YOURLS点击查看免费下载相关推荐登录脚本里的硬编码密码有多危险深入解析ScriptSentry凭据检测规则登录脚本里的硬编码密码有多危险深入解析ScriptSentry凭据检测规则 在 Windows 域环境中登录脚本Logon Script会在每台电脑开机BigFunctions数据转换大全20个数组处理函数让你的SQL更强大BigFunctions数据转换大全20个数组处理函数让你的SQL更强大 BigFunctions是一款能够Supercharge BigQuery的开源工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考