使用 DataBlock 探索真实世界 API
Source: Dev.to
请提供您希望翻译的完整文本内容(除代码块和 URL 之外),我将按照要求将其翻译成简体中文并保留原有的格式。
我们将使用的工具
- GitHub API – 仓库统计
- Packagist API – 下载统计和热门包
- 来自 GitHub 的原始
composer.json文件
所有请求将使用 Symfony HTTP Client 发出,让 DataBlock 包装响应。
Required packages
composer require hi-folks/data-block symfony/http-client
- DataBlock – 完全与框架无关;可在纯 PHP、Symfony 或任何其他环境中使用。
- Symfony HTTP Client – 实现
Symfony\Contracts\HttpClient\HttpClientInterface。
使用 DataBlock 获取 JSON
DataBlock 为 HTTP JSON 源提供了一个便利的助手:
Block::fromHttpJsonUrl(string $url, HttpClientInterface $client);
为什么这种设计很重要
- 可互换的客户端 – 任何实现了
HttpClientInterface的客户端都可以使用(Symfony HttpClient、模拟客户端、自定义实现)。 - 可测试的代码 – 你可以注入一个假的客户端。
- 解耦 – 没有对具体客户端的硬编码依赖。
- 框架无关 – DataBlock 与 Symfony 无关,保持独立。
创建 HTTP 客户端
use HiFolks\DataType\Block;
use Symfony\Component\HttpClient\HttpClient;
$httpClient = HttpClient::create([
'headers' => [
'User-Agent' => 'PHP DataBlock',
'Accept' => 'application/json',
],
]);
现在你可以直接将该客户端传递给 DataBlock:
Block::fromHttpJsonUrl($url, $httpClient);
具体示例:Symfony 与 Laravel
我们将查询两个公共生态系统:
| 来源 | 接口地址 |
|---|---|
| GitHub – Symfony 仓库 | https://api.github.com/repos/symfony/symfony |
| GitHub – Laravel 仓库 | https://api.github.com/repos/laravel/framework |
| Packagist – Symfony 统计 | https://packagist.org/packages/symfony/symfony/stats.json |
| Packagist – Laravel 统计 | https://packagist.org/packages/laravel/framework/stats.json |
每个接口返回一个包含众多嵌套字段的大型 JSON 文档——非常适合演示 DataBlock。
获取数据
// GitHub 数据
$symfonyGithub = Block::fromHttpJsonUrl(
'https://api.github.com/repos/symfony/symfony',
$httpClient,
);
$laravelGithub = Block::fromHttpJsonUrl(
'https://api.github.com/repos/laravel/framework',
$httpClient,
);
// Packagist 统计
$symfonyStats = Block::fromHttpJsonUrl(
'https://packagist.org/packages/symfony/symfony/stats.json',
$httpClient,
);
$laravelStats = Block::fromHttpJsonUrl(
'https://packagist.org/packages/laravel/framework/stats.json',
$httpClient,
);
从此以后我们不再直接操作原始数组——DataBlock 负责所有导航和类型转换。
显示 GitHub 统计信息
// Symfony
echo "Symfony GitHub:\n";
echo "Stars: " . $symfonyGithub->getInt('stargazers_count') . "\n";
echo "Forks: " . $symfonyGithub->getInt('forks_count') . "\n";
echo "Open issues: " . $symfonyGithub->getInt('open_issues_count') . "\n";
echo "Main language: " .
$symfonyGithub->getString('language', 'unknown') . "\n";
// Laravel
echo "Laravel GitHub:\n";
echo "Stars: " . $laravelGithub->getInt('stargazers_count') . "\n";
echo "Forks: " . $laravelGithub->getInt('forks_count') . "\n";
echo "Open issues: " . $laravelGithub->getInt('open_issues_count') . "\n";
echo "Main language: " .
$laravelGithub->getString('language', 'unknown') . "\n";
没有 isset() 检查,没有 PHP 警告,也不需要手动类型转换——意图清晰。
显示 Packagist 下载统计
Packagist 的 JSON 将下载数字嵌套在 downloads 对象下。使用普通数组时需要多次 isset() 检查:
$data['downloads']['total'];
$data['downloads']['monthly'];
$data['downloads']['daily'];
DataBlock 让我们可以使用点号表示法:
// Symfony 下载
echo "Symfony downloads:\n";
echo "Total: " . $symfonyStats->getInt('downloads.total') . "\n";
echo "Monthly: " . $symfonyStats->getInt('downloads.monthly') . "\n";
echo "Daily: " . $symfonyStats->getInt('downloads.daily') . "\n";
// Laravel 下载
echo "Laravel downloads:\n";
echo "Total: " . $laravelStats->getInt('downloads.total') . "\n";
echo "Monthly: " . $laravelStats->getInt('downloads.monthly') . "\n";
echo "Daily: " . $laravelStats->getInt('downloads.daily') . "\n";
同样,没有脆弱的 isset() 结构——DataBlock 保证安全访问并进行正确的类型转换。
要点
- DataBlock 抽象了遍历深层嵌套 JSON 结构的繁琐工作。
- Symfony HttpClient 提供了符合标准、兼容 PSR 的 HTTP 层,可与 DataBlock 无缝配合。
- 通过将传输层(HTTP 客户端)与数据处理层(DataBlock)分离,代码保持 清晰、可测试、且 不依赖特定框架。
随时可以将 Symfony 客户端替换为其他实现了 HttpClientInterface 的客户端;其余示例代码无需更改。祝编码愉快!
使用点符号处理 JSON
echo $elStats->getInt("downloads.daily") . "\n";
这里好处在于 JSON 的结构在代码中 几乎消失 了。
你不必在意结构有多深层嵌套;只需描述想要的值的路径即可。
- 点符号 将深层嵌套的文档转换为看起来平坦、可读且易于推理的形式,同时仍保持安全和类型感知。
Source: …
直接从 GitHub 获取 composer.json 文件
$symfonyComposer = Block::fromHttpJsonUrl(
"https://raw.githubusercontent.com/symfony/symfony/master/composer.json",
$httpClient,
);
$laravelComposer = Block::fromHttpJsonUrl(
"https://raw.githubusercontent.com/laravel/framework/master/composer.json",
$httpClient,
);
使用 getString() 获取类型化(字符串)值
echo "Symfony PHP requirement: " .
$symfonyComposer->getString("require.php") .
"\n";
echo "Laravel PHP requirement: " .
$laravelComposer->getString("require.php") .
"\n";
探索依赖关系
$symfonyRequires = $symfonyComposer->getBlock("require");
$laravelRequires = $laravelComposer->getBlock("require");
print_r($symfonyRequires->keys());
print_r($laravelRequires->keys());
这是一种 结构化文档探索,而不仅仅是普通数组访问。
处理结构化项目集合
我们使用的 Packagist 端点返回的是 100 个最受欢迎的包的列表,即一个 嵌套数据集,而不是单个对象。
$url = "https://packagist.org/explore/popular.json?per_page=100";
$popularPackages = Block::fromHttpJsonUrl($url, $httpClient)
->getBlock("packages");
选择与 Symfony 和 Laravel 相关的包
$symfonyPopularPackages = $popularPackages
->where("name", Operator::LIKE, "symfony")
->orderBy("favers", "desc");
$laravelPopularPackages = $popularPackages
->where("name", Operator::LIKE, "laravel")
->orderBy("favers", "desc");
where() 方法
根据条件过滤数据集:
->where(field, operator, value)
示例
->where("name", Operator::LIKE, "symfony")
仅保留 name 字段包含 “symfony” 这个词的项目。
$popularPackages 中的每个元素本身都是一个结构化对象(包条目),DataBlock 会对所有这些对象应用该条件。
Operator 枚举
定义比较应如何进行:
| 枚举 | 含义 |
|---|---|
Operator::EQUAL | 等于 |
Operator::NOT_EQUAL | 不等于 |
Operator::GREATER_THAN | 大于 |
Operator::LESS_THAN | 小于 |
Operator::LIKE | 字符串包含(此处使用) |
| …以及其他… |
使用枚举而非原始字符串可以让 API:
- 更安全 – 避免拼写错误
- 更明确 – 意图清晰
- 更易发现 – IDE 自动补全可用
orderBy() 方法
在过滤之后,对结果进行排序:
->orderBy("favers", "desc")
按 favers 字段的降序对剩余项目进行排序,使星标最多的包排在最前面。
因为 where() 和 orderBy() 的返回仍然是一个 Block,所以可以继续使用所有相同的工具:计数、访问嵌套字段以及安全读取值。
检查结果
echo "Popular Packages:\n";
echo "Symfony: " . $symfonyPopularPackages->count() . PHP_EOL;
echo " High Favers: " .
$symfonyPopularPackages->getString("0.name", "") .
" - " .
$symfonyPopularPackages->getInt("0.favers", 0) .
PHP_EOL;
echo "Laravel: " . $laravelPopularPackages->count() . PHP_EOL;
echo " High Favers: " .
$laravelPopularPackages->getString("0.name", "") .
" - " .
$laravelPopularPackages->getInt("0.favers", 0) .
PHP_EOL;
回顾
此时我们已经拥有:
- Filtered 真实数据集
- Sorted 按有意义的字段对它们进行排序
- Counted 并检查结果
- Navigated 深度嵌套结构
—全部 从未触碰原始数组。
为什么使用 DataBlock?
- 支持 本地数组/文件 以及 远程 JSON/YAML(API 响应、外部文档)。
- 将数据包装在
DataBlock中后,你可以:- 安全地访问深层嵌套的值
- 过滤数据集
- 排序并检查结果
- 只提取你真正关心的部分
所有这些 无需担心键缺失、结构破损或手动类型转换。
DataBlock并不试图取代 DTO 或业务逻辑。它的职责简单而专注:让结构化数据——无论来源——更容易且更安全地进行探索、查询和使用。
参考文献
- PHP DataBlock GitHub repository –
- Laravel News article –
- Previous article – Handling Nested PHP Arrays Using DataBlock –