PHP code example of xiasf / think-orm
1. Go to this page and download the library: Download xiasf/think-orm library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
xiasf / think-orm example snippets
\ThinkOrm\Orm::boot([
'database' => [
'type' => 'mysql',
'hostname' => '127.0.0.1',
'hostport' => 3306,
'database' => 'app',
'username' => 'root',
'password' => 'secret',
'charset' => 'utf8mb4',
'prefix' => '',
'debug' => false,
],
]);
// 文件: app/model/User.php
namespace app\model;
use app\common\BaseModel;
use think\traits\model\SoftDelete;
class User extends BaseModel
{
use SoftDelete;
protected $table = 'users';
protected $deleteTime = 'delete_time';
protected $hidden = ['password'];
protected $readonly = ['name'];
// 关联(直接用类常量,IDE 可跳转、PHPStan 可静态分析)
public function posts() { return $this->hasMany(Post::class); }
public function profile() { return $this->hasOne(Profile::class); }
public function roles() { return $this->belongsToMany(Role::class, 'user_roles'); }
}
$User = model('User');
$User->add(['name' => 'tom', 'email' => 't@x']); // 创建(带自动时间戳 + 验证场景 add)
$User->upds([['id' => 1, 'age' => 20], ...]); // 批量更新
$User->info(1); // 单条查询
$User->infoBy(['mobile' => '13800138000']); // 条件查询单条
$User->listPageBy(['is_active' => 1], 'id,name', 1, 20); // 分页列表
$User->countBy(['status' => 1]); // 条件计数
$User->valueBy(['id' => 1], 'name'); // 单值查询
$User->inc(['id' => 1], 'hits', 1); // 自增
$User->upSert(['uniq_key' => 'k1', 'val' => 'v1']); // 不存在则插入,存在则更新
namespace app\model;
use think\Model;
use think\traits\model\SoftDelete;
class User extends Model
{
use SoftDelete;
protected $table = 'users';
protected $autoWriteTimestamp = 'datetime';
protected $deleteTime = 'delete_time';
protected $hidden = ['password'];
protected $readonly = ['name'];
public function posts() { return $this->hasMany(Post::class); }
public function getNameAttr($v) { return ucfirst($v); }
public function scopeActive($q) { return $q->where('is_active', 1); }
}
// 取模型实例(单例)
$User = model('User');
// CRUD
$user = $User->find(1);
$users = $User->where('age', '>', 18)->order('id desc')->select();
$newId = $User->insertGetId(['name' => 'a', 'email' => 'a@x']);
$User->where('id', $newId)->update(['age' => 20]);
// 或走静态
$user = \app\model\User::get(1);
$user->age = 21;
$user->save();
\app\model\User::destroy([2, 3]);
// 关联
foreach (\app\model\User::get(1)->posts as $p) { /* ... */ }
// 验证
$v = validate('User');
if (!$v->check($data)) {
echo $v->getError();
}
// 文件: app/validate/User.php
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => '填',
'name.max' => '名字不能超过 30 字符',
'email' => '邮箱格式错误',
];
protected $scene = [
'create' => ['name', 'email', 'age'],
'update' => ['name', 'age'],
'login' => ['email'],
];
}
validate('User')->scene('login')->check(['email' => '[email protected] ']);
\think\App::$namespace = 'My\\App'; // model('User') → My\App\model\User
namespace app\parkinglot\model\v1;
use app\parkinglot\model\BModel;
use app\parkinglot\model\v1\Smartpark;
class Car extends BModel
{
// 关联:直接用类常量 Smartpark::class —— 比 model('xxx/xxx')->class 更直接,
// IDE 可跳转、PHPStan 可静态分析。
public function smartparkInfo()
{
return $this->belongsTo(Smartpark::class, 'smartpark_id', 'id')
->where(['status' => 1, 'is_del' => 0]);
}
}
// example/app/parkinglot/model/BModel.php
class BModel extends BaseModel
{
public $model = null; // 必须为 public(否则被 __set 拦截)
protected $readonly = ['smartpark_id', 'parkinglot_id'];
public function smartparkInfo()
{
return $this->belongsTo(Smartpark::class, 'smartpark_id', 'id')
->where(['status' => 1, 'is_del' => 0]); // 条件关联
}
public function useWithSp() // 链式预加载快捷方法
{
return $this->useWith(['smartpark_info', 'parkinglot_info']);
}
}
class Car extends BModel
{
protected $insert = ['is_temp_number', 'is_new_energy'];
// 显式传值则尊重,否则按车牌号推断
protected function setIsTempNumberAttr($value, $data)
{
if (is_null($value) || $value === '') {
return stripos($data['number'] ?? '', '临') === false ? 0 : 1;
}
return $value;
}
}
public function userInfo()
{
return $this->belongsTo(User::class, 'user_id', 'id')->bind([
'name', 'face', 'email', 'mobile', 'nick_name', 'real_name',
]);
}
public function carOwnerList()
{
$rel = $this->belongsToMany(CarOwner::class, 'pt_car_car_owner', 'car_owner_id', 'car_id');
$sp = Request::instance()->param('smartpark_id/d', 0);
if ($sp) {
$rel->getQuery()->where(['pivot.smartpark_id' => $sp]);
}
return $rel;
}
public function useWithFull()
{
return $this->useWith([
'smartpark_info',
'fixcar_list' => ['smartpark_info', 'parkinglot_info'], // 二级嵌套
'car_owner_list',
]);
}
protected function validateData($data, $rule = null, $batch = null)
{
// ...build $validate...
set_error_handler(function ($code, $msg, $file, $line) {
// iconv 转 GBK→utf-8 后抛 ValidateException
throw new ValidateException("Validate ERROR: [{$code}] {$msg} in file: {$file} on line: {$line}");
});
try {
$ok = $validate->batch($batch)->check($data);
} finally {
restore_error_handler();
}
// ...
}
\ThinkOrm\Orm::boot([
'database' => [
'type' => 'mysql', // 本包仅支持 mysql
'hostname' => '127.0.0.1',
'hostport' => 3306,
'database' => 'app',
'username' => 'root',
'password' => '',
'dsn' => '', // 显式 dsn 优先
'socket' => '', // Unix socket(非空时优先于 hostname/hostport)
'charset' => 'utf8mb4',
'prefix' => '',
'params' => [], // PDO 构造参数,例:[PDO::ATTR_PERSISTENT => true] 开持久连接
'debug' => false,
'deploy' => 0, // 0=集中式(单库),1=分布式(主从)
'rw_separate' => false, // 分布式部署时是否读写分离
'master_num' => 1, // 主服务器数量(rw_separate=true 时有效)
'slave_no' => '', // 指定从服务器序号(不指定则随机)
'read_master' => false, // 写后强制读主库(业务有"写完立即读"场景时启用)
'fields_strict' => true, // 严格字段检查
'resultset_type' => 'array', // 或 'collection'
'auto_timestamp' => false, // 全局自动时间戳
'datetime_format' => 'Y-m-d H:i:s',
'sql_explain' => false, // EXPLAIN 调试(debug=true 时生效)
'use_schema' => false, // 读取 RUNTIME_PATH/schema 字段缓存
'builder' => '', // 自定义 Builder 类
'query' => '\\think\\db\\Query', // 自定义 Query 类
'break_reconnect' => false, // 断线重连
],
'paginate' => [
'type' => 'bootstrap',
'var_page' => 'page',
'list_rows' => 15,
],
]);
// boot 之前先定义,否则自动 fallback 到 sys_get_temp_dir()/think-orm/
define('RUNTIME_PATH', '/var/log/myapp/');
\ThinkOrm\Orm::boot([...]);
\ThinkOrm\Orm::boot([
'database' => [
// ...
'params' => [\PDO::ATTR_PERSISTENT => true], // ★ 开
'break_reconnect' => false, // ★ 不依赖
'read_master' => true, // 业务有写后立即读就开
],
]);
\ThinkOrm\Orm::boot([
'database' => [
// ...
'params' => [], // ★ 关(不能开 persistent)
'break_reconnect' => true, // ★ 必须开
'read_master' => true,
],
]);
protected function initDb(): void
{
Db::query('SELECT 1'); // 强制建立连接(避免 lazy 引发首次业务请求即失败)
$this->lastHeartbeat = microtime(true);
}
while (!$this->stopRequested) {
try {
if (microtime(true) - $this->lastHeartbeat >= $this->heartbeatInterval) {
$this->heartbeat(); // SELECT 1,失败抛 PDOException
$this->lastHeartbeat = microtime(true);
}
$this->onTick(); // 业务
} catch (\Throwable $e) {
if ($this->checkDbBreak($e)) { // 关键词识别
$this->reconnectDb();
}
}
}
protected function reconnectDb(): void
{
// 1) 清全局连接池
Db::clear();
// 2) 清 Model 类级别 Query 缓存(protected,反射)
$prop = new \ReflectionProperty(Model::class, 'links');
$prop->setAccessible(true);
$prop->setValue(null, []);
// 3) 强制重建一次连接(失败立即抛)
Db::query('SELECT 1');
}
$keywords = [
'server has gone away', 'no connection to the server',
'Lost connection', 'is dead or not enabled',
'Error while sending', 'decryption failed or bad record mac',
'server closed the connection unexpectedly',
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided', 'failed with errno',
'Broken pipe',
];
// PSR-3 SQL 日志
\think\Log::setLogger($monolog);
// PSR-16 让 Query::cache() 真正生效
\think\Cache::setInstance($psr16Cache);
// 自定义 Request(用于 Paginator 解析 page 参数、Validate::method)
\think\Request::setInstance(new MyRequest());
User::destroy($ids, true); // 第二参数 $force=true 走 SoftDelete::destroy 第二参
$user->delete(true); // SoftDelete::delete($force=true) 跳过软删字段
User::onlyTrashed()->select(); // 反例:查软删记录用 onlyTrashed()
example/app/
├── di/
│ ├── model/
│ │ └── v1/
│ │ ├── Notice.php ← model('di/v1/Notice') 或 model('di/v1/notice')
│ │ └── Smartpark.php
│ └── validate/
│ └── Notice.php
├── parkinglot/
│ ├── model/
│ │ ├── BModel.php ← 不通过 model() 解析(直接 use)
│ │ └── v1/
│ │ ├── Car.php ← model('parkinglot/v1/Car')
│ │ ├── CarOwner.php
│ │ └── ...
│ └── validate/
│ ├── BaseValidator.php
│ └── Car.php ← validate('parkinglot/Car')
└── common/
└── BaseModel.php
bash
# demo 模式(限 20 个 tick 后退出)
php example/run_daemon.php --max-tick=20
# 生产模式(无限循环;pcntl 可用时 SIGTERM/SIGINT 优雅退出)
php example/run_daemon.php
bash
mysql -u root -p123456 -e "CREATE DATABASE think_orm_example CHARSET utf8mb4"
php example/run.php
bash
# 复用 example 数据库
php example/run_daemon.php --max-tick=20 # demo 模式:跑 20 个 tick 后退出
php example/run_daemon.php # 生产模式:无限循环(Ctrl+C 退出)