Download the PHP package xiasf/think-orm without Composer

On this page you can find all versions of the php package xiasf/think-orm. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package think-orm

think-orm

Packagist Version PHP Version Total Downloads Monthly Downloads Packagist Stars GitHub Stars GitHub Issues Last Commit CI

ThinkPHP 5.0.24 ORM 的独立 composer 包移植。保留原 think\ 命名空间,零改动拷贝核心源码,配套 8 个桩文件替换框架依赖。

官方 topthink/think-orm 从 TP 5.1+ 抽出,API 与 5.0.24 不兼容,因此必须直接 fork 5.0.24 实际源码。


安装

需要 PHP >= 7.2 + ext-pdo。MySQL 默认 ext-pdo_mysql


三步上手

1. 启动

2. 创建模型(默认解析到 app\<module>\model\<Name>

⚠️ 强烈建议:yf 项目直接继承 app\common\BaseModel,不要继承 think\Model

BaseModel 在 think\Model 之上封装了 yf 业务高频方法(add / adds / upd / upds / updBy / updAttr / del / info / infoBy / lists / listBy / listByIds / listPageBy / search / search_or / countBy / maxBy / minBy / avgBy / sumBy / valueBy / inc / dec / upSert / resultSet / resultListSet),统一了 CRUD 入口、自动时间戳、错误处理、验证场景、字段格式化等约定。

直接继承 think\Model 是反模式:会丢掉 yf 项目的统一调用风格、错误转异常、validatorName 推断等关键能力。

推荐做法:继承 app\common\BaseModel

业务调用全部走 BaseModel 统一 API:

BaseModel 的核心能力(详见 example/app/common/BaseModel.php

能力 说明
统一 CRUD 入口 add/adds/upd/upds/updBy/updAttr/del/delBy 替代散落的 insert/update/delete
统一查询入口 info/infoBy/lists/listBy/listByIds/listPageBy/search/search_or
统一聚合 countBy/maxBy/minBy/avgBy/sumBy/valueBy
统一自增减 inc/dec
upSert 不存在则插入、存在则更新
自动时间戳 autoWriteTimestamp = 'datetime' 默认开启
字段格式化 resultSet 把 decimal 转 float、JSON 字段自动 decode、append 字段追加
验证场景自动推断 从命名空间推断 validatorName()(如 app\parkinglot\model\v1\Carparkinglot/Car
错误转异常 validateData() 包了 set_error_handler,规则写错抛 ValidateException 而非静默
trait spd/sca 子类实现 get_Scope() / get_withModel() / get_ExtendField() 等 hook

拷贝到自己的项目:BaseModel 不在 src/ 里(它是业务层而非框架层)。把 example/app/common/BaseModel.phpexample/app/common/traits/model/Model.php 复制到你项目的 app/common/ 下即可。完整业务参考见 example/app/parkinglot/(BModel + 条件关联 + pivot 过滤 + 多层 with)。

仅在简单脚本场景直接继承 think\Model

如果你的项目只是想用 ORM,不需要 yf 风格 CRUD:

3. 用 model() / validate() 操作


创建验证器(默认解析到 app\validate\<Name>


命名空间与 model()/validate() 解析

model() / validate() 解析器有 4 种输入形式,所有形式都自动把下划线命名转成大驼峰

调用 解析结果 目录
model('user') app\model\User app/model/User.php
model('user_order') app\model\UserOrder app/model/UserOrder.php(下划线 → 大驼峰)
model('iot/xxx') app\iot\model\Xxx app/iot/model/Xxx.php(模块/名字)
model('iot/user_order') app\iot\model\UserOrder app/iot/model/UserOrder.php
model('iot/v1/xxx') app\iot\model\v1\Xxx app/iot/model/v1/Xxx.php(多层路径)
model('iot/v1/user_order') app\iot\model\v1\UserOrder app/iot/model/v1/UserOrder.php
model('\\App\\Special\\User') 原样使用 直接 new 这个类

转换规则(Loader::parseName

验证器同规则

validate('iot/Car')app\iot\validate\Carvalidate('iot/v1/CarOrder')app\iot\validate\v1\CarOrder

自定义命名空间根

默认根命名空间是 app(由 App::$namespace 控制)。如果你的项目不叫 app

common 模块 fallback

如果 model('iot/NotExists') 在 iot 模块下找不到,Loader 会自动尝试 app\common\model\NotExists。这是 yf 的多模块共享模型机制。

实际例子(yf 项目风格)

历史写法 model('smartpark/smartpark')->class 也能用(model() 返回实例,->class 取其 FQCN),但不推荐——多一次实例化、绕一道字符串解析、IDE 无法跟踪。新代码统一用 TargetClass::class

文件结构:


yf 风格业务模块参考:parkinglot example

example/app/parkinglot/ 是从 yf 真实业务抽出来的最小可运行参考,覆盖以下高级模式(每个都有对应测试):

1. BModel:双 readonly + 默认关联

2. $insert 自动字段 + 修改器(默认值兜底)

3. belongsTo + ->bind() 字段绑定

把关联表字段"绑"成本模型字段,访问 $owner->name 实际取自 user 表:

4. belongsToMany + pivot 条件过滤

通过 Request::instance()->param('smartpark_id/d') 在运行时给 pivot 加条件:

5. 多层嵌套 with

6. 7 个 yf 风格验证规则(BaseValidator

规则 语义 示例
sometimes 字段存在时才校验(TP 默认行为已涵盖,这里仅作声明) 'mobile' => 'sometimes\|regex:^1\d{10}$'
conflict:a,b 当前字段存在时,a/b 都不能存在 'email' => 'conflict:mobile,name'
r_if:field,v1,v2 field 等于 v1 或 v2 时当前字段必填 'mobile' => 'r_if:contact_type,phone,sms'
r_with:a,b a 或 b 存在时当前字段必填 'nick_name' => 'r_with:name,email'
r_with_all:a,b a 和 b 都存在时当前字段必填 同上
r_without:a,b a 或 b 不存在时当前字段必填 同上
r_without_all:a,b a 和 b 都不存在时当前字段必填 同上

本包的 Validate::checkItem 已扩展:所有 r_* 规则即使在字段为空时也会触发(默认 TP 行为只对 require* 规则如此)。这是与上游 TP 5.0.24 的唯一行为差异,但完全是 yf 业务必需的。

7. BaseModel::validateData 错误转异常

规则写错(如 'require|integeregt:0' 拼错)时,原 TP 5.0.24 会触发 PHP Warning 然后静默通过。本包的 BaseModel 用 set_error_handler 包裹,转成 ValidateException 便于排查:


配置

数据库(完整选项)

与 yf 项目 database.php 对齐:上面列出的配置项与 TP 5.0.24 / yf 项目惯例完全一致。从 yf 切到本包时,把 yf 的 application/database.php 返回数组直接传给 Orm::boot(['database' => $yfConfig]) 即可。

自定义常量


守护进程使用

适用场景:workerman / swoole / while(true) loop / cron 等 CLI 常驻进程。

核心问题:常驻进程持有 PDO 连接数小时,MySQL wait_timeout(默认 8h,DBA 可能调到 1h 甚至更短)会主动切断空闲连接,下次 query 时炸 MySQL server has gone away

关键配置:phpfpm vs cli

配置项 phpfpm / mod_php cli 守护进程
params[PDO::ATTR_PERSISTENT] true(多请求间复用 PDO,减握手) 不设 / [](守护进程已常驻,persistent 反而阻止 break_reconnect 关闭僵尸连接)
break_reconnect false(请求短,靠重建连接即可) true(必须开,遇到 gone away 关键词自动 close → 重连)
read_master 按需 true(守护进程有"写后立即读"场景的几乎必然)

phpfpm 启动

cli 守护进程启动

为什么 cli 不能开 ATTR_PERSISTENT

  1. 守护进程本来就常驻,PDO 已天然复用,persistent 不带来额外收益
  2. persistent PDO 由 PHP 内部缓存Connection::close() 只是 $this->linkID = null不真关闭底层 PDO。break_reconnect 失效,僵尸连接永远占着
  3. persistent 连接跨脚本共享,多个 worker 进程(如 workerman 多子进程)共用同一个 PHP 持久化池容易撞 transaction 状态污染

完整守护进程 demo

参考 example/daemon/BaseWorker.php —— 单文件、零外部依赖、不依赖 pcntl(Windows 也能跑)。三个核心机制:

1. initDb():启动时预连接

2. heartbeat():定期探活

3. reconnectDb():清两道缓存

踩过的坑break_reconnect = trueConnection::close() 只清自己内部的 linkID,但 Model::$links 是另一个静态缓存,按 model 类名缓存了 Query 实例(持有 Connection)。Connection 重建后,Model 仍会拿到老的僵尸 Connection。

checkDbBreak 关键词列表

参考 Connection::isBreak()

业务异常(如 validate failed)不应触发重连 —— checkDbBreak 用 stripos 匹配关键词,无匹配返回 false。

完整启动示例

参考文件:


注入(可选)

未注入时所有调用都走 NoOp 桩,不报错。


API 速查

用法 例子
模型实例 model('User')
验证器实例 validate('User')
单条 User::get($id) / User::where('x',1)->find()
多条 User::all() / User::where(...)->select()
单值 User::where('id',1)->value('name')
列值 User::column('name','id')
插入 User::create($data) / (new User)->save($data)
更新 User::update($data) / $u->save()
删除 User::destroy($ids) / $u->delete()
物理删除(含软删模型) User::destroy($ids, true) / $u->delete(true) —— 注意 不是 force()->delete()(见下方差异说明)
自增自减 User::where('id',1)->inc('hits')->update()
关联 User::with('posts,profile')->select()
分页 User::where(...)->paginate(15)
事务 Db::transaction(fn() => ...) —— 异常抛出
事务(yf 风格 helper) transaction(fn() => ..., $errMsg, $errCode, $exception) —— 异常转引用传出,失败返回 false
分批 User::chunk(100, function($rows){...})
软删恢复 User::onlyTrashed()->find()->restore()

测试

跑 example

example/run.php 端到端演示:model() 解析 → 创建 → 字段格式化(JSON/数组/decimal→float/append)→ 关联预加载 → readonly → 验证器场景 → 聚合。包含 13 个 section:di 模块(Notice/Smartpark)+ parkinglot 模块(Car/CarOwner/Parkinglot/Smartpark/User 的 BModel + 条件关联 + bind + 多层嵌套 + pivot 过滤 + readonly)。所有 SQL 通过 PSR-3 logger 打到 stdout。

跑守护进程示例

example/run_daemon.php 演示守护进程下安全使用 ORM 的完整模式:队列消费 worker,每 2 秒轮询一批任务、单条事务处理、失败回滚、定期心跳、断线重连。详见下方 守护进程使用 章节。

测试覆盖(435 tests / 855 assertions):

范围 测试文件
桩文件 SupportStubTest
配置 ConfigTest
Loader 类 LoaderTest(parseName / parseClass / addNamespaceAlias / addClassMap / model() / validate() 解析、缓存、common fallback、FQCN passthrough、异常)
验证规则 ValidateRulesTest(全部内置规则 + 中文消息)
集合 CollectionTest
CRUD QueryCrudTestInsertAllTest
事务 TransactionTest(commit/rollback/嵌套 + yf 风格 transaction() helper 4 个场景)
Query Builder QueryBuilderTest(where/join/group/having/order/limit/page/inc/dec)
Query 高级 API AdvancedQueryTest(whereRaw/whereOrRaw/whereExists/whereNotExists/whereExp/whereTime/whereNotNull/whereNotBetween/whereNotLike/useSoftDelete/fetchSql/getPk/getTableFields)
子查询 SubqueryTest
分批 ChunkCursorTest
Model CRUD ModelCrudTestModelAccessorMutatorTestModelAutoTimestampTest
Model 高级 ModelWorkflowTestmodel()/validate() helper、hidden/append、scope、事件、readonly)
Model 高级 API AdvancedApiTest(Paginator URL 辅助:appends/fragment/getUrlRange/getCurrentPage/getCurrentPath/render;Model::has / hasWhere / together)
验证器 ModelValidationTest(Model 内嵌规则 + 失败回滚)
软删 SoftDeleteTest
关联 RelationHasOneTestRelationHasManyTestRelationBelongsToTestRelationBelongsToManyTestRelationHasManyThroughTestRelationMorphTest
复合主键 ComplexPkTest
JSON 字段 JsonFieldTest
分页 PaginatorTest
闭包 where ClosureWhereTest
yf 风格 BaseModel YfBaseModelTest(77 个测试:validatorName、useWith、自动时间戳、JSON、读写器、append、关联、readonly、CRUD add/adds/upd/upds/updBy/updAttr/del/delBy、info/infoBy、lists/listBy/listByIds/listPageBy、search/search_or 分页、聚合 countBy/maxBy/minBy/avgBy/sumBy/valueBy/inc/dec、upSert、resultSet/resultListSet、trait spd/sca/listIndexBy/listIndexByIds/fieldWhere/withModel/withScope/get_ExtendField/rollbackQuery、validatorName 显式覆盖、validateData 错误转异常、PSR-3 SQL 日志、validate/model helper、端到端)
yf parkinglot 模块 ParkinglotIntegrationTest(20 个测试:BModel 双 readonly + 条件关联 + helper,$insert 自动字段 + 修改器,belongsTo+bind,hasMany,belongsToMany+pivot 过滤,多层嵌套 with,search_or,7 个 BaseValidator 自定义规则,validateData 错误转异常)
守护进程 DaemonWorkerTest(15 个测试:initDb/heartbeat 探活、checkDbBreak 关键词识别 gone away/lost connection/broken pipe、业务异常不触发重连、reconnectDb 双缓存清空 Db::$instance+Model::$links、重建 PDO(CONNECTION_ID 变化)、cli 默认关 persistent / phpfpm 通过 params 开 persistent、限次迭代生命周期、心跳触发、模拟断线自动重连恢复)

与原 TP 5.0.24 的差异

  1. helper.php 精简:保留 exception / config / dump / debug / model / validate / db / import / trace / load_relation / collection,删除 web 相关助手(lang/input/widget/controller/action/url/session/cookie/cache/request/response/view/json/jsonp/xml/redirect/abort/halt/token/load_trait/vendor)。
  2. Config.php:移除依赖 Request::module() 的动态 extra-config 加载分支。
  3. Validate.php$typeMsg 改为硬编码中文;移除 {%xxx%} 多语言包装与 Lang::get/has 调用。
  4. behavior 规则:本包未移植 think\Hook 类。Validate::behavior() 直接返回 true(规则视为通过);如需自定义行为验证,覆盖该方法即可。
  5. token 规则:依赖 Session,桩默认返回 null,token 规则将失败;可注入 Session 实现启用。
  6. Paginator:默认 Request::param() 桩返回 null,页码默认为 1;要支持 HTTP 上下文需注入自定义 Request。
  7. Validate::checkItem 扩展:所有以 r_ 开头的规则(r_if / r_with / r_with_all / r_without / r_without_all)即使在字段为空时也会触发——这是 yf 业务必需的条件必填语义。原 TP 5.0.24 只对 require* 规则做此处理,本包扩展至 r_*
  8. Loader.php:移除了 register() / loadComposerAutoloadFiles() / registerComposerLoader() 等 SPL autoload 注册逻辑——Composer 已处理自动加载。Loader::model() 在跨模块查找时的 EXTEND_PATH/APP_PATH 改为读项目根的 extend/app/ 目录。
  9. trait 命名空间迁移:原 TP 5.0.24 的 traits\model\SoftDeletetraits\think\Instance 占用顶层 traits\ 命名空间,不适合作为公开 composer 包发布。本包改为:

    • traits\model\SoftDeletethink\traits\model\SoftDelete
    • traits\think\Instancethink\traits\Instance(同时整理目录结构)

    从 yf 迁移过来的代码需把 use traits\model\SoftDelete; 改为 use think\traits\model\SoftDelete;

  10. Query::setInc / setDec 实时写入:移除了 $lazyTime 延迟累积更新分支(依赖 Cache 的 inc/dec),inc/dec 永远实时写入 DB。$lazyTime 参数保留以维持签名兼容但被忽略。
  11. 不依赖缓存think\Cache 桩默认所有操作返回 false / null / 空。Query::cache() API 保留(每次仍走 DB),PSR-16 缓存可选注入但不推荐。
  12. ⚠️ Orm::boot() 只能初始化一次:第二次调用仅合并 Config不会刷新这些已建立的单例:

    • Log::$logger(已注入的 PSR-3 logger)
    • Db::$instance(已建立的 PDO 连接)
    • Model::$links(按类名缓存的 Query 实例)

    Log::record 的"按优先级"行为(重要):

    • 未注入 PSR-3 logger → 走文件日志(如已通过 log.file 启用)
    • 已注入 PSR-3 logger → 直接调用 logger->log()return文件日志永远不写(即使 log.file 也配置了)
    想运行时切换: 场景 正确做法
    切日志文件路径(未注入 PSR-3 logger) Orm::refreshLog($newPath) 或直接 Log::setLogFile($newPath)
    切 PSR-3 logger 实例 Log::setLogger($newLogger)
    从 PSR-3 logger 切回文件日志 Log::setLogger(null) + Log::setLogFile($path)
    多套 DB 配置 Db::connect($configKey) 显式连接(不要重复 boot 切库)
    守护进程断线重连 见 守护进程使用 章节
    测试场景完全重置 Orm::reset() + Db::clear() + 反射清空 Model::$links
  13. ⚠️ force() 是 update 标志,不是物理删除Laravel 用户最容易踩的坑):
    • $model->force(true)->save() —— 跳过字段比较,强制 update 写入(TP 5.0.24 原语义)
    • $model->force()->delete() —— 仍是软删,force 标志对 delete 无影响
    • 物理删除(含软删模型)的真实 API:

License

Apache-2.0(同 ThinkPHP 5.0.24)。


All versions of think-orm with dependencies

PHP Build Version
Package Version
Requires php Version >=7.2
ext-pdo Version *
ext-pdo_mysql Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package xiasf/think-orm contains the following files

Loading the files please wait ...