承接 nandan108/prop-path 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

nandan108/prop-path

Composer 安装命令:

composer require nandan108/prop-path

包简介

A composable, JSONPath-inspired query engine for deep property access in PHP

README 文档

README

CI Coverage Style Packagist Psalm Level

TL;DR PropPath is a powerful query engine for PHP that lets you extract deeply nested values from arrays and objects using concise, expressive syntax. Inspired by JSONPath but tailored for modern PHP, it supports recursive traversal, multi-key mapping, fallback resolution, bracket grouping, and structured mode — all compiled into fast, reusable closures.

What is PropPath?

PropPath is a feature-rich, extensible query engine for extracting values from complex PHP object graphs, arrays, or a mix of both. Inspired by JSONPath and built for modern PHP codebases, PropPath compiles string-based or structured path expressions into efficient extractor closures that traverse nested structures using a powerful set of operators.

It powers advanced features in the DTO Toolkit, enabling concise and expressive mapping between input payloads and strongly typed DTOs.

Use cases and philosophy

PropPath is designed for:

  • Structured data extraction from deeply nested objects or mixed arrays
  • Declarative field mapping in DTO systems, data transformation layers, or form normalizers
  • Reusable compiled resolvers, allowing precompiled paths to be cached or reused

It follows a few guiding principles:

  • Minimalism: Do one thing well — extract values, not transform or mutate them.
  • Expressive and powerful: Supports structured extraction, shallow and recursive wildcards, multi-key mapping, fallback resolution, flattening, and more.
  • Clarity over magic: Although expressive, the syntax is designed to be predictable and consistent.

📦 Installation

composer require nandan108/prop-path

🚀 Quick Start

PropPath compiles a path string (or structured array) into an extractor closure:

use Nandan108\PropPath\PropPath;
$roots = ['dto' => ['user' => ['email' => 'jane@example.com']]];
$extractor = PropPath::extract('$dto.user.email', $roots);
// $email === 'jane@example.com'

The compiled closure takes an associative array of roots as its argument.

📚 Nested Example

$data = [
    'dto' => [
        'user' => [
            'name' => 'Jane',
            'email' => 'jane@example.com',
            'addresses' => [
                'home' => ['city' => 'Geneva', 'zip' => '1201'],
                'office' => ['city' => 'Vernier', 'zip' => '1214', 'phone' => '1234'],
            ],
        ],
    ],
    'context' => ['request' => ['search' => 'foo']],
];

$extractor = PropPath::compile('$dto.user.addresses.home.city');
$homeCity = $extractor($data); // 'Geneva'

// direct extraction:
PropPath::extract('$dto.user["homeCity" => addresses.home.city]', $data);
// ['homeCity' => 'Geneva']

PropPath::extract('user[
    // extract map of zip codes by city name from addresses
    "zips"  => addresses[*[city => zip]]@~,
    // get value of first "phone" field anywhere in structure,
    // (default to "no phone")
    "phone" => [**phone ?? "no phone"],
    "fax"   => [**fax ?? "no fax"],
    // grab "search" => request.search from $context (not default root)
    $context.request.@search
]', $data);
// $result === [
//     'zips' => ['Geneva' => '1201', 'Vernier' => 1214],
//     'phone' => '1234',
//     'fax' => 'no fax',
//     'search' => 'foo',
// ];

🧩 Syntax Reference

Find the full syntax reference at docs/Syntax.md

🧵 Structured Mode

Instead of a single path string, you can pass an array structure:

$roots = ['root' => ['path' => ['a', 'b', 'c']]];
$result = PropPath::extract(['foo' => 'path.0', ['path.1', ['path.2']]], $roots);
// ['foo' => 'a', ['b', ['c']]]

This allows you to mirror a desired shape without building complex bracket paths.

🧠 How It Compares to JSONPath

PropPath is inspired by JSONPath but diverges where needed for better PHP ergonomics:

Feature JSONPath PropPath
Root marker $ $, $dto, $context, etc.
Wildcard * *, with depth control
Recursive descent .. **
Filters 🔸 Not supported (may be added later via symfony/expression-language)
Multi-key extraction [foo, bar] or ['x' => path]
Fallback resolution (??)
Array flattening ~, @~
Structured input mode

🧠 Container-agnostic access JSONPath uses different syntax to access objects vs arrays. PropPath does not. It uses a unified syntax for all container types (arrays, objects, or ArrayAccess).

Brackets in PropPath do not indicate container type — they serve to:

  1. Build arrays from multiple values
  2. Group expressions for correct evaluation order For example, foo.*.bar.0 applies .0 per item. [foo.*.bar].0 applies .0 to the overall result.

📌 Performance Notes

PropPath compiles each path into a memoized closure using an xxh3-based hash. Structured and recursive queries (**) may be slower; typical paths are fast and safe to cache.

⚙️ Tooling + Integration

🛠 API Reference

PropPath::compile(string|array $paths, ...): \Closure
PropPath::extract(string|array $paths, array $roots, ...): mixed
PropPath::clearCache(): void
PropPath::boot(): void

Evaluation Failures

PropPath::compile() returns an extractor with this shape:

fn (array $roots, ?Closure $failEvalWith = null): mixed

Custom evaluation handlers receive a failure snapshot as second argument:

use Nandan108\PropPath\Support\EvaluationFailureDetails;

$extractor = PropPath::compile('!user.email');

$value = $extractor($roots, function (string $message, EvaluationFailureDetails $failure): never {
    // Example: machine-readable code + normalized path
    throw new RuntimeException($failure->code->value.' at '.$failure->getPropertyPath());
});

When using the default handler, EvaluationError exposes machine-readable fields:

try {
    PropPath::extract('!missing', ['value' => []]);
} catch (\Nandan108\PropPath\Exception\EvaluationError $e) {
    $code = $e->getErrorCode();               // EvaluationErrorCode enum
    $params = $e->getMessageParameters();     // includes "errorCode", often "key"/"containerType"
    $path = $e->getPropertyPath();            // e.g. "$value.missing"
    $debug = $e->getDebugInfoMap();
}

✅ Quality

  • 100% test coverage
  • Psalm: level 1 (the strictest)
  • Code style enforced with PHP-CS-Fixer:
    • Based on the @Symfony rule set
    • Aligned => for better readability
    • Disallows implicit loose comparisons (==, !=)

📄 License and Attribution

MIT License © nandan108 Author: Samuel de Rougemont

nandan108/prop-path 适用场景与选型建议

nandan108/prop-path 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 205 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 06 月 29 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 nandan108/prop-path 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 nandan108/prop-path 我们能提供哪些服务?
定制开发 / 二次开发

基于 nandan108/prop-path 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 205
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 16
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-06-29