jsonobject
jsonobject
は、JSON 定義からのオブジェクトの使用を容易にする PHP クラスです。このアイデアは、Python でpydantic
使用することと、json データを解析して検証してオブジェクトにする機能から生まれました。
jsonobject
なのかPHP の API を使用する必要があり、その API からjsonobjectが返されました。したがって、それらをアプリで使用できる PHP オブジェクトに解析する必要がありました。
ワークフローは
jsonobject
使用して JSON 定義を解析する次の JSON の例を見てみましょう。
{
"id" : 0 ,
"name" : " John Doe " ,
"age" : 42 ,
"emails" : [
" [email protected] " ,
" [email protected] "
],
"address" : {
"street" : " My street " ,
"number" : 42 ,
"city" : " My city " ,
"country" : " My country "
}
}
jsonobject
を使用すると、次のクラスを使用してデータ モデルを定義できます。
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
];
}
class Address extends jsonobject {
const ATTRIBUTES = [
' street ' => ' str ' ,
' number ' => ' int ' ,
' city ' => ' str ' ,
' country ' => ' str ' ,
];
}
そして、次のコマンドを追加します。
$ user = User:: fromObject ( json_decode ( $ json_text_definition ));
jsonobject
クラスは、コンテンツをオブジェクトに解析して実行し、その属性を定義どおりに使用できるようになります。
echo ( $ user -> name );
定義されたクラスには、アプリケーションのデータ モデルの実装を容易にするメソッドを含めることもできます。たとえば、次のようにUser
クラスを定義することができます。
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
];
public function isAdult () {
return $ this -> age >= 18 ;
}
}
jsonobject
の使用jsonobject
クラスの考え方は、これを使用してjsonデータをオブジェクトに解析することです。そのため、これらのオブジェクトには、アプリケーションのデータ モデルの実装に役立つ他のメソッドが含まれる可能性があります。
json オブジェクト (または配列) が解析されるとき、その内容はATTRIBUTES
定数で定義された型に従って再帰的に解析されます。データが無効な場合は、予期された値が含まれていないため、例外がスローされます。
jsonobject使用するには、 jsonobject
をサブクラス化し、そのクラスのATTRIBUTES
定数を定義して、そのクラスのオブジェクトに予期される属性とそれぞれの型を定義する必要があります。
ATTRIBUTES
定数は、キーが各属性の名前、値が各属性の型である連想配列です。
考えられるタイプは次のとおりです。
jsonobject
のサブクラスである必要があるクラス名です。属性の名前を定義するときに、 ?
名前の末尾に、属性がオプションであることを示します。たとえば、属性名address?
ユースケースセクションのはオプションです。
各フィールドは必須とみなされ、解析されたオブジェクト (または配列) 内に存在する必要があります。さらに、オブジェクトは定義された型である必要があります (つまり、特定の型によって正しく解析される必要があります)。
オプションではない属性は、必須であるとみなされます。これは次の 2 つの点で特に興味深いです。
fromArray
関数またはfromObject
関数を使用)。jsonobject
のオブジェクトまたは配列表現を生成するとき外部構造からオブジェクトを作成する場合、 jsonobject
すべての必須フィールドを処理します。それらのいずれかが欠落している場合は、例外が発生します。
次の例では、必須フィールドの年齢が指定されていないため、例外が発生します。
class User extends jsonobject {
const ATTRIBUTES = [
" name " => " str " ,
" age " => " int " ,
];
}
( . . . )
$ user = User:: fromArray ([ " name " => " John " ]);
オブジェクトを配列またはオブジェクトに変換するとき (またはその JSON 表現を取得するとき)、必須フィールドは、設定されていない場合でもデフォルト値を取得します。
したがって、次の例では
class User extends jsonobject {
const ATTRIBUTES = [
" name " => " str " ,
" age " => " int " ,
" birthDate? " => " str "
];
}
$ user = new User ();
echo (( string ) $ user );
出力は次のようになります
{
"name" : " " ,
"age" : 0
}
なぜなら、属性nameとage は必須であり、デフォルト値 (つまり、数値の場合は 0、文字列、リスト、または辞書の場合は空) を取得するのに対し、属性birthDateは必須ではなく、まだ設定されていないからです。したがって、出力には生成されません。
null
を設定する値をnullに設定する問題は、属性がオプションであるかどうかを考慮するときに特に関係します。
値をnullに設定すると、値の設定が解除されることになるため、必須の値ではなくオプションの値に対してのみ可能であるべきだと考える人もいるかもしれません。
jsonobject
では、異なる概念があります。プロパティをnullに設定することは、「値をnullに設定する」ことを意味し、プロパティの設定を解除することを意味しないからです。プロパティの設定を解除するには、関数 unset などを使用する必要があります。
jsonobject
、値の設定を解除することもできます。オプションの属性の場合、これは値を削除することを意味するため、配列表現またはオブジェクトには値がありません (値を取得する場合は、 nullに設定されます)。
ただし、必須属性の場合、設定を解除すると、その値がデフォルトにリセットされることになります。これは、型のデフォルト値 (つまり、数値の場合は 0、リスト、文字列、または辞書の場合は空など)、またはATTRIBUTES
定数のデフォルト値に初期化されることを意味します。
jsonobject
は、親クラスから属性を継承することもできます。次の例を見てみましょう。
class Vehicle extends jsonobject {
const ATTRIBUTES = [
" brand " => " str " ,
" color " => " str "
]
}
class Car extends Vehicle {
const ATTRIBUTES = [
" wheels " => " int "
]
}
class Boat extends Vehicle {
const ATTRIBUTES = [
" length " => " float "
]
}
この例では、クラスVehicle
はbrandおよびcolor属性のみが含まれますが、 Car
クラスにはbrand 、 color 、およびホイール属性が含まれ、クラスBoat
はbrand 、 color 、およびlength属性があります。
jsonobject
の子クラスのオブジェクトは、静的メソッド::fromArray
または::fromObject
を使用して、 json解析済みオブジェクトから作成できます。
前の例では、次の内容を含むファイルcar.jsonがあるとします。
{
"brand" : " BMW " ,
"color" : " black "
}
次のコードを使用して、 Vehicle
クラスのインスタンスを取得できます。
$ json = file_get_contents ( " car.json " );
$ vehicle = Vehicle:: fromArray (( array ) json_decode ( $ json , true ));
別の方法は、次の例のようにオブジェクトをインスタンス化することです。
* PHP 8以降:
$ car = new Car (brand: " BMW " , color: " black " , wheels: 4 );
*以前の PHP バージョン:
$ car = new Car ([ " brand " => " BMW " , " color " => " black " , " wheels " => 4 ]);
jsonobject
jsonobject
は、このライブラリのコア クラスです。そのメソッドは次のとおりです。
__construct($data)
- 指定されたデータから新しいオブジェクトを作成します__get($name)
- 指定された名前の属性の値を返します__set($name, $value)
- 指定された名前の属性の値を設定します__isset($name)
- 指定された名前の属性が設定されている場合は true を返します__unset($name)
- オプションの属性の値の設定を解除します (または必須の属性の値をリセットします)。toArray()
- オブジェクトのデータを含む連想配列を返します。配列は再帰的に作成され、各属性の各サブ属性にアクセスします。toObject()
- オブジェクトのデータを属性として持つオブジェクトを返します。配列は再帰的に作成され、各属性の各サブ属性にアクセスします。toJson()
- オブジェクトの表現を標準オブジェクトとして含む json 文字列を返します。::fromArray($data)
- 指定された連想配列をクラスで定義された属性に解析して、オブジェクトを作成します。各属性は、定義されたタイプに従って再帰的に解析されます。::fromObject($data)
- 指定されたオブジェクトをクラスで定義された属性に解析して、オブジェクトを作成します。各属性は、定義されたタイプに従って再帰的に解析されます。 JsonDict
このオブジェクトは、JSON 定義からの辞書を処理するために使用されます。 JsonDict
クラスは、各要素が特定の型である必要があるように型指定されます。
JsonDict
オブジェクトは配列のようなオブジェクト ($jsonDict["key1"] など) として使用できますが、(このテキストを書いている時点では) 辞書に挿入された要素の型はチェックされません。この型は、辞書の作成時にコンテンツを解析するため (たとえば、 fromArray
静的関数を使用)、またはコンテンツを配列またはオブジェクトにダンプするため (たとえば、 toArray
関数を使用) に使用されます。
方法は次のとおりです。
toArray()
toObject()
::fromArray($data)
::fromObject($data)
これらのメソッドは、 jsonobject
の場合と同じ方法で解釈されます。また、辞書内の要素の型は、コンテンツを解析するときに再帰的に考慮される複合型を参照する場合があります。
たとえば、type list[list[int]]
[ [ 1, 2, 3], [ 4, 5, 6 ]]
の解析に使用されます。
JsonArray
このオブジェクトはJsonDict
とほとんど同じですが、インデックスが整数でなければならない点が異なります。この場合、 $value["key1"]
例外を生成します。
この場合、配列に要素を追加する関数 (つまり[]
) も実装されます。
クラスを定義するときに、新しく作成されたオブジェクトの値と、オプションの属性を初期化することができます。
次の 2 つの方法があります。
### クラスプロパティの使用
クラスのプロパティを使用してオブジェクトの値を初期化できるため、属性の値がクラスに設定されている場合、その値は属性としてインスタンスにコピーされます (定義されている場合)。
例えば
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
' sex? ' => ' str '
];
public $ sex = " not revealed " ;
}
現在、属性sex
nullではなく、明らかにされないように初期化されます。
これを作成する方法は、オブジェクトのタイプのタプル[ <type>, <default value> ]
を定義することです。次の例を見てみましょう。
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
' sex? ' => [ ' str ' , ' not revealed ' ]
];
}
ユーザーデータを取得する場合、 sex
属性はオプションです。クラスにこの新しい定義を使用すると、 sex
が設定されていない場合、値はnull
ではなく「非公開」に設定されます。
重要な機能は、 <default value>として設定された文字列がオブジェクトのメソッドに対応する場合、値を取得するときに (まだ設定されていない場合)、その文字列が呼び出され、そのプロパティに設定された値が呼び出しの結果になります。
例えば
class User extends jsonobject {
const ATTRIBUTE = [
...
' birthDay? ' => [ ' str ' , ' computeBirthDate ' ]
]
function computeBirthDate () {
$ now = new DateTime ();
$ now ->sub( DateInterval ::createFromDateString("{ $ this -> age } years"));
return $ now ->format("Y-m-d");
}
}
この例では、 birthDate
プロパティを設定していなかったが取得された場合、現在の日付から年齢を減算することによって計算されます。
任意のオブジェクトをjsonobject
に解析したい場合は、関数jsonobject ::parse_typed_value
を使用できます。これは、任意の型からjsonobject
型に変換できるようにするために重要です。
例えば
$ myobject = jsonobject :: parse_typed_value ( " list[str] " , [ " my " , " name " , " is " , " John " ]);
JsonList<str>
型のオブジェクトを取得します。
このライブラリのデフォルトの動作では、属性に設定された値がその定義されたタイプと一致することが保証されます。しかし、それは、 float
int
ではないため、 float を0
に設定すると、 0
整数であるため失敗することを意味します。その場合、ユーザーは値を割り当てる前に値をキャストする必要があります。型を厳密にチェックするかどうかを制御するには、定数STRICT_TYPE_CHECKING
を使用できます。
STRICT_TYPE_CHECKING
がTrue
に設定されている場合、型は厳密にチェックされ、たとえば9.3
int
に代入すると例外が発生します。False
に設定すると、数値型が相互に変換されます。たとえば、9.3
int
に代入すると、自動的に9
に切り捨てられます。
その他の重要な型チェックは、空の値 (つまり""
またはnull
) を数値型に割り当てるときです。その場合、定数STRICT_TYPE_CHECKING_EMPTY_ZERO
があります。
STRICT_TYPE_CHECKING_EMPTY_ZERO
がTrue
(デフォルトの動作) に設定されている場合、空の値を数値型に割り当てるとき、その値は0
とみなされます。つまり、空の文字列またはnull
値をint
属性に割り当てることは、0
割り当てることを意味します。False
に設定すると、ライブラリは型をチェックし、最終的に例外を発生させます。
JsonList
負のインデックスも使用できるようになり、 -1
最後の要素、 -2
最後から 2 番目などになります。
JsonList
オブジェクトには、並べ替えまたはフィルター処理の関数が含まれています。
public function sort(callable $callback = null) : JsonList
: 指定されたコールバックを使用してリストを並べ替えます。コールバックが指定されていない場合は、デフォルトの比較関数を使用してリストを並べ替えます。public function filter(callable $callback) : JsonList
: 指定されたコールバックを使用してリストをフィルターします。コールバックはブール値を返す必要があります。コールバックがtrue
を返す場合、要素は結果のリストに含まれます。 false
返した場合、要素は破棄されます。