jasny/dotkey

对象和数组的点表示法访问

v2.2.0 2024-09-03 21:04 UTC

This package is auto-updated.

Last update: 2024-09-03 22:03:26 UTC


README

jasny-banner

DotKey

PHP Scrutinizer Code Quality Code Coverage Packagist Stable Version Packagist License

对象和数组的点表示法访问。

灵感来源于 node.js Dotty 库。

安装

composer require jasny/dotkey

使用

use Jasny\DotKey\DotKey;

$subject = [
  "a" => [
    "b" => [
      "x" => "y"
    ]
  ]
];

DotKey::on($subject)->exists("a.b.x");        // true
DotKey::on($subject)->exists("a.b.z");        // false
DotKey::on($subject)->exists("a.b.x.o");      // false

DotKey::on($subject)->get("a.b.x");           // "y"
DotKey::on($subject)->get("a.b");             // ["x" => "y"]
DotKey::on($subject)->get("a.b.z");           // null
DotKey::on($subject)->get("a.b.x.o");         // Throws ResolveException because a.b.x is a string

DotKey::on($subject)->set("a.b.q", "foo");    // $subject = ["a" => ["b" => ["x" => "y", "q" => "foo"]]]
DotKey::on($subject)->set("a.d", ['p' => 1]); // $subject = ["a" => ["b" => ["x" => "y"]], "d" => ["p" => 1]]
DotKey::on($subject)->set("a.c.x", "bar");    // Throws ResolveException because a.c doesn't exist
DotKey::on($subject)->set("a.b.x.o", "qux");  // Throws ResolveException because a.b.x is a string

DotKey::on($subject)->put("a.b.q", "foo");    // $subject = ["a" => ["b" => ["x" => "y", "q" => "foo"]]]
DotKey::on($subject)->put("a.c.x", "bar");    // $subject = ["a" => ["b" => ["x" => "y"]], "c" => ["x" => "bar"]]

DotKey::on($subject)->remove("a.b.x");        // $subject = ["a" => ["b" => []]]
DotKey::on($subject)->remove("a.c.z");        // $subject isn't modified
DotKey::on($subject)->remove("a.b.x.o");      // Throws ResolveException because a.b.x is a string
DotKey::on($subject)->remove("a.b");          // $subject = ["a" => []]

DotKey::on($subject)->update("a.b", fn($value) => array_map('strtoupper', $value)); // $subject = ["a" => ["b" => ["x" => "Y"]]]

主题可以是数组或对象。如果对象实现了 ArrayAccess,它将被视为数组。

use Jasny\DotKey\DotKey;

$obj = (object)["a" => (object)["b" => (object)["x" => "y"]]];

DotKey::on($obj)->exists("a.b.x");
DotKey::on($obj)->set("a.b.q", "foo");

exists() 在尝试访问私有或静态属性时会返回 false。所有其他方法都会抛出 ResolveException

复制

默认情况下,目标会在原地修改。使用 onCopy() 工厂方法,会创建一个副本。

use Jasny\DotKey\DotKey;

$source = ["a" => ["b" => ["x" => "y"]]];

DotKey::onCopy($source, $copy)->set("a.b.q", "foo");  // $copy = ["a" => ["b" => ["x" => "y", "q" => "foo"]]]

使用 onCopy(),如果对象被修改,将会克隆对象。

use Jasny\DotKey\DotKey;

$source = (object)["f" => (object)["x" => "y"], "g" => (object)["x" => "z"]]]];

DotKey::onCopy($source, $copy)->set("f.q", "foo");

$copy === $source;       // false, source is cloned
$copy->f === $source->f; // false, `f` is cloned and modified
$copy->g === $source->g; // true, `g` is not cloned

分隔符

默认分隔符是点,但可以使用任何字符串作为分隔符。会去除开头和结尾的分隔符。

use Jasny\DotKey\DotKey;

DotKey::on($subject)->exists('/a/b/x', '/');
DotKey::on($subject)->get("/a/b/x", '/');
DotKey::on($subject)->set("/a/b/q", "foo", '/');
DotKey::on($subject)->put("/a/b/q", "foo", '/');
DotKey::on($subject)->remove("/a/b/q", '/');

DotKey::on($subject)->exists('a::b::c', '::');

设置 vs 插入

  • set('a.b.c', 1) 需要 'a.b' 存在并且是对象或数组。如果不是这种情况,将抛出 ResolveException
  • put('a.b.c', 1) 总是会导致 $result["a"]["b"]["c"] === 1。如果 'a.b' 不存在,它将被创建。如果它已经存在并且不是数组或对象,它将被覆盖。

put() 创建的结构要么是关联数组,要么是 \stdClass 对象,具体取决于主题的类型。将 true 作为第四个参数传递将强制将其转换为数组,而将 false 传递将强制创建一个对象。

use Jasny\DotKey\DotKey;

$subject = ["a" => null];
$obj = (object)["a" => null];

DotKey::on($subject)->put("a.b.o", 1, '.');        // ["a" => ["b" => ["o" => 1]]]
DotKey::on($subject)->put("a.b.o", 1, '.', true);  // ["a" => ["b" => ["o" => 1]]]
DotKey::on($subject)->put("a.b.o", 1, '.', false); // ["a" => (object)["b" => (object)["o" => 1]]]

DotKey::on($obj)->put("a.b.o", 1, '.');            // (object)["a" => (object)["b" => (object)["o" => 1]]]
DotKey::on($obj)->put("a.b.o", 1, '.', true);      // (object)["a" => ["b" => ["o" => 1]]]
DotKey::on($obj)->put("a.b.o", 1, '.', false);     // (object)["a" => (object)["b" => (object)["o" => 1]]]