erikwang2013 / clickhouse-php
A full-featured PHP ClickHouse client with HTTP and Native TCP support, query builder, schema builder, migration system, and ORM.
v1.0.2
2026-05-27 10:40 UTC
Requires
- php: >=8.1
- guzzlehttp/guzzle: ^7.0
- psr/log: ^3.0
Requires (Dev)
- mockery/mockery: ^1.5
- phpunit/phpunit: ^10.0
Suggests
- hyperf/framework: For Hyperf integration (^3.0)
- laravel/framework: For Laravel integration (^10.0|^11.0)
- topthink/framework: For ThinkPHP integration (^8.0)
- workerman/workerman: For Webman integration (^4.0)
README
PHP ClickHouse 客户端,支持 HTTP 与 Native TCP 双协议,内置查询构建器、Schema Builder、迁移系统和 ORM,深度适配 Laravel、ThinkPHP、Webman、Hyperf。
安装
composer require erikwang2013/clickhouse-php
快速开始
独立使用
use Erikwang2013\ClickHouse\ClickHouse; use Erikwang2013\ClickHouse\Client\Manager; // 配置 $config = [ 'default' => 'clickhouse', 'connections' => [ 'clickhouse' => [ 'driver' => 'http', // http 或 native 'host' => 'localhost', 'port' => 8123, // HTTP 端口, Native 用 9000 'database' => 'default', 'username' => 'default', 'password' => '', 'timeout' => 30, ], ], ]; // 初始化 $manager = new Manager($config); ClickHouse::setManager($manager); // 查询 $rows = ClickHouse::table('logs') ->where('date', '>=', '2024-01-01') ->whereIn('level', ['error', 'warn']) ->orderBy('timestamp', 'desc') ->limit(100) ->get(); foreach ($rows as $row) { echo $row['message']; } // 原生 SQL $result = ClickHouse::query('SELECT count(*) AS cnt FROM logs WHERE date = ?', ['2024-01-01']); echo $result->first()['cnt']; // 聚合 $count = ClickHouse::table('logs')->where('level', 'error')->count(); $avgDuration = ClickHouse::table('logs')->avg('duration');
插入数据
// 单行 ClickHouse::table('logs')->insert([ 'date' => '2024-01-01', 'level' => 'info', 'message' => 'hello', 'duration' => 12.5, ]); // 批量 ClickHouse::table('logs')->insert([ ['date' => '2024-01-01', 'level' => 'info', 'message' => 'a', 'duration' => 1.2], ['date' => '2024-01-02', 'level' => 'error', 'message' => 'b', 'duration' => 3.4], ]);
建表 (Schema Builder)
ClickHouse::schema()->create('logs', function ($table) { $table->date('date'); $table->dateTime('timestamp'); $table->string('level'); $table->string('message'); $table->float64('duration'); $table->engine('MergeTree') ->partitionBy('toYYYYMM(date)') ->orderBy(['date', 'timestamp', 'level']); }); // 删除表 ClickHouse::schema()->drop('logs'); // 修改表 ClickHouse::schema()->alter('logs', function ($table) { $table->nullable('source', 'String'); });
数据迁移
创建迁移文件(如 2026_05_27_000000_create_logs_table.php):
use Erikwang2013\ClickHouse\Migration\Migration; class CreateLogsTable extends Migration { public function up(): void { $this->schema->create('logs', function ($table) { $table->date('date'); $table->string('level'); $table->engine('MergeTree') ->partitionBy('toYYYYMM(date)') ->orderBy(['date', 'level']); }); } public function down(): void { $this->schema->drop('logs'); } }
运行迁移:
use Erikwang2013\ClickHouse\Migration\Migrator; use Erikwang2013\ClickHouse\Migration\Repository; $client = ClickHouse::getManager()->connection(); $repository = new Repository($client); $migrator = new Migrator($client, $repository, '/path/to/migrations'); $migrator->install(); // 创建迁移记录表 $migrator->run(); // 执行待迁移 $migrator->rollback(); // 回滚上一批 $migrator->refresh(); // 回滚后重新执行
ORM
use Erikwang2013\ClickHouse\ORM\Model; class Log extends Model { protected string $table = 'logs'; protected string $connection = 'default'; } // 查询 $logs = Log::where('level', 'error') ->orderBy('timestamp', 'desc') ->limit(50) ->get(); // 查找单条 $log = Log::find(123); // 聚合 $total = Log::where('date', '>=', '2024-01-01')->count(); // 批量插入 Log::insert([ ['date' => '2024-01-01', 'level' => 'info'], ['date' => '2024-01-02', 'level' => 'error'], ]);
多连接
$config = [ 'default' => 'default', 'connections' => [ 'default' => ['driver' => 'http', 'host' => 'ch1.example.com', 'port' => 8123], 'analytics' => ['driver' => 'http', 'host' => 'ch2.example.com', 'port' => 8123], ], ]; $manager = new Manager($config); // 使用指定连接 ClickHouse::connection('analytics')->table('events')->get(); ClickHouse::table('events', 'analytics')->get();
框架集成
Laravel
配置文件自动发布,Composer 自动发现 ServiceProvider。
php artisan vendor:publish --tag=clickhouse-config
use Erikwang2013\ClickHouse\Laravel\Facades\ClickHouse; ClickHouse::table('logs')->where('level', 'error')->get(); ClickHouse::connection('native')->select('SELECT * FROM logs LIMIT 10');
Artisan 命令:
php artisan clickhouse:table-list php artisan clickhouse:migration:install php artisan clickhouse:migration:run
ThinkPHP
在 app/service.php 中注册服务:
return [ \Erikwang2013\ClickHouse\ThinkPHP\ClickHouseService::class, ];
use think\facade\ClickHouse; ClickHouse::table('logs')->get();
php think clickhouse:table-list
Webman
Webman 自动加载插件配置,无需手动配置。
use Erikwang2013\ClickHouse\Webman\ClickHouse; ClickHouse::table('logs')->where('level', 'error')->get();
Hyperf
通过 ConfigProvider 自动发现,支持依赖注入和协程连接池。
php bin/hyperf.php vendor:publish erikwang2013/clickhouse-php
use Erikwang2013\ClickHouse\Hyperf\ClickHouseConnection; class LogController { public function __construct( private ClickHouseConnection $clickhouse ) {} public function index() { return $this->clickhouse->table('logs')->get(); } }
查询构建器参考
| 方法 | 说明 |
|---|---|
table($name) / from($name) |
指定表名 |
select([...]) / selectRaw($expr) |
SELECT 列 |
where($col, $op, $val) |
条件 (2 参数时 $op 默认 =) |
orWhere($col, $op, $val) |
OR 条件 |
whereIn($col, $arr) / whereNotIn($col, $arr) |
IN / NOT IN |
whereBetween($col, [$min, $max]) |
BETWEEN |
whereNull($col) / whereNotNull($col) |
IS NULL / IS NOT NULL |
whereRaw($sql) |
原生 WHERE |
orderBy($col, $dir) |
排序 (默认 ASC) |
groupBy(...$cols) |
分组 |
limit($n) / offset($n) |
分页 |
count() / sum($col) / avg($col) / min($col) / max($col) |
聚合 |
insert($data) |
插入 (单行或批量) |
delete() |
删除 |
get() |
执行查询,返回 Result |
first() |
返回第一条 |
toSql() |
获取生成的 SQL |
Schema 列类型
| 方法 | ClickHouse 类型 |
|---|---|
string($name) |
String |
fixedString($name, $len) |
FixedString(N) |
int8/16/32/64($name) |
Int8/16/32/64 |
uint8/16/32/64($name) |
UInt8/16/32/64 |
float32($name) / float64($name) |
Float32 / Float64 |
decimal($name, $p, $s) |
Decimal(P, S) |
date($name) |
Date |
dateTime($name) |
DateTime |
dateTime64($name, $p) |
DateTime64(P) |
uuid($name) |
UUID |
bool($name) |
Bool |
array($name, $type) |
Array(T) |
nullable($name, $type) |
Nullable(T) |
lowCardinality($name, $type) |
LowCardinality(T) |
配置参考
[
'default' => 'clickhouse',
'connections' => [
'clickhouse' => [
'driver' => 'http', // http | native
'host' => 'localhost',
'port' => 8123, // HTTP 8123, Native 9000
'database' => 'default',
'username' => 'default',
'password' => '',
'timeout' => 30,
],
],
'pool' => [
'min_connections' => 2,
'max_connections' => 16,
'connection_timeout' => 5.0,
],
'query_log' => false,
];
环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
CLICKHOUSE_HOST |
localhost | 主机地址 |
CLICKHOUSE_PORT |
8123 | HTTP 端口 |
CLICKHOUSE_DB |
default | 数据库名 |
CLICKHOUSE_USER |
default | 用户名 |
CLICKHOUSE_PASS |
— | 密码 |
CLICKHOUSE_TIMEOUT |
30 | 连接超时(秒) |
CLICKHOUSE_DRIVER |
http | 驱动类型 |
CLICKHOUSE_POOL_MIN |
2 | 最小连接数 |
CLICKHOUSE_POOL_MAX |
16 | 最大连接数 |
异常处理
use Erikwang2013\ClickHouse\Exceptions\{ ClickHouseException, ConnectionException, QueryException, TimeoutException, PoolException, }; try { ClickHouse::table('logs')->get(); } catch (ConnectionException | TimeoutException $e) { // 连接或超时问题 } catch (QueryException $e) { echo $e->getMessage(); echo $e->getSql(); // 原始 SQL } catch (ClickHouseException $e) { // 其他异常 }
许可证
MIT License. Copyright (c) 2026 erik erik@erik.xyz — https://erik.xyz