使用 DataBlock 探索真实世界 API

发布: (2026年1月7日 GMT+8 03:57)
8 min read
原文: Dev.to

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 articleHandling Nested PHP Arrays Using DataBlock
Back to Blog

相关文章

阅读更多 »