4D オブジェクトまとめ
4D v16R4でオブジェクト(JSON)をドット式(オブジェクト記法)でアクセスできるようになりました。これでオブジェクトを本格的に使うためのツールが揃った感じです。
でも、4Dのオブジェクトは少々扱いが変わっていまして通常の数値やテキストとは違っています。
この記事のようにオブジェクトは基本、参照型のデータですので振る舞いが違っています。そこで、それをまとめてみました。上記記事も内容が古く、一部間違っていますので、それも訂正しつつまとめます。
なおv15.4の場合の動作です。
○オブジェクトの初期化
v16R4ではNew Objectというコマンドが導入されて明示的にオブジェクトのインスタンスを作成できますが、v15では少々微妙です。
C_OBJECT($obj)
で、オブジェクト型の変数を宣言できますが、この状態ではインスタンスはありません。
OB SET($obj;"abc";111)
で、インスタンスができます。また、
$obj:=JSON Parse("{\"abc\":111}")
でも、インスタンスができます。
CLEAR VARIABLE($obj)
で、インスタンスはなくなり未定義となります。
$obj:=JSON Parse("{}")
では、空のオブジェクトのインスタンスができます。
○オブジェクトは参照
オブジェクトは参照ですので、変数に代入した場合、インスタンスが渡されるのではなくインスタンスへの参照が渡されます。
OB SET($obj;"abc";111)
$ObjB := $obj
OB SET(&obj;"abc";222)
とすると、$objも$ObjBも同じインスタンスを指しているので、{"abc":222}というオブジェクトになります。もちろん
OB SET($obj;"abc";111)
$ObjB := $obj
OB SET(&ObjB;"abc";222)
としても結果は同じです。
OB SET($obj;"abc";111)
$ObjB := $obj
$objK:=$ObjB
OB SET(&ObjB;"abc";222)
とすると、$objも$ObjBも$objKも3つとも同じになります。
別のインスタンスとして扱うには
と書いてインスタンスを明示的にコピーします。OB SET($obj;"abc";111)
$ObjB := OB Copy($obj)
OB SET(&obj;"abc";222)
// $obj {"abc":222}
// $ObjB {"abc":111}
変数は配列の要素でも同じです。
ARRAY OBJECT($aObj;0)
OB SET($obj;"abc";123)
APPEND TO ARRAY($aObj;$obj)
OB SET($obj;"abc";999)
APPEND TO ARRAY($aObj;$obj)
とすると、$objも$aObj{1}も$aObj{2}も{"abc";999}になります。
同様に
ARRAY OBJECT($aObj;2)
OB SET($obj;"abc";123)
$aObj{1}:=$obj
OB SET($obj;"abc";999)
$aObj{2}:=$obj
としても、$objも$aObj{1}も$aObj{2}も{"abc";999}になります。ここが最初の記事と違う部分です。要素への追加の仕方が変わっても参照であることは変わりません。
ARRAY OBJECT($aObj;2)
OB SET($aObj{1};"abc";123)
OB SET($aObj{2};"abc";999)
このように、要素オブジェクトを直接修正した場合は、要素ごとに違ったインスタンスとなります。
ARRAY OBJECT($aObj;2)
OB SET($obj;"abc";123)
$aObj{1}:=OB Copy($obj)
OB SET($obj;"abc";999)
$aObj{2}:=OB Copy($obj)
明示的にインスタンスをコピーしても要素ごとに別のインスタンスになります。
配列のコピーも参照です。
ARRAY OBJECT($aObj;0)
OB SET($obj;"abc";123)
APPEND TO ARRAY($aObj;$obj)
OB SET($obj;"abc";999)
APPEND TO ARRAY($aObj;$obj)
COPY ARRAY($aObj;$aObj2)
OB SET($aObj2{2};"abc";888888)
とすると、配列$aObjの全要素、配列$aObj2の全要素、$objが全て{"abc":888888}となります。
ARRAY OBJECT($aObj;0)
OB SET($obj;"abc";123)
APPEND TO ARRAY($aObj;$obj)
OB SET($obj;"abc";999)
APPEND TO ARRAY($aObj;OB Copy($obj))
COPY ARRAY($aObj;$aObj2)
OB SET($aObj2{2};"abc";888888)
と、片方を別のインスタンスにすると、$aObjと$aObj2の1番目の要素は変化しません。
C_BLOB($myblob)
SET BLOB SIZE($myblob;0)
VARIABLE TO BLOB($aObj;$myblob*)
$off:=0
BLOB TO VRIABLE($myblob;$aObj2;$ff)
OB SET($aObj{2};"abc";888888)
というように、BLOBを使って配列をコピーした場合は、別のインスタンスになりますので、$aObj2{2}は変化しません。これは、VARIABLE TO BLOBでオブジェクトをBLOBに格納する場合は参照ではなくインスタンスをUTF8で文字列化して保存するためです。
○メソッドの引数も参照渡し
メソッドの引数も参照渡しです。
//subR($1)
C_OBJECT($1)
OB SET($1;"abc";8888)
というメソッドがあって
OB SET($obj;"abc";1)
subR($obj)
を実行すると、$objは{"abc":8888}となります。
呼び出し側でインスタンスがない変数を指定した場合は
CLEAR VARIABLE($obj)
subR($obj)
は、$objは未定義のままです。
$obj:=JSON Parse("{}")
subR($obj)
と空のオブジェクトを渡した場合は、期待どおり、{"abc";8888}となります。
○レコード中のオブジェクト
レコードのオブジェクトはカレントレコードだけがインスタンスとなります。
QUERY([Table];[Table]ID=10)
$obj:=[Table]Obj
OB SET($obj;"abc";8888)
とすると$objもカレントレコードの[Table]Objも{"abc":8888}です。SAVEすれば、レコードには{"abc":8888}が保存されます。SAVEを繰り返してもカレントレコードはアンロードされませんので参照は維持されます。
カレントレコードがアンロードされるとその時点で参照が切れて新しいインスタンスになります。
QUERY([Table];[Table]ID=10)
$obj:=[Table]Obj
UNLOAD RECORD([TABLE])
QUERY([Table];[Table]ID=10)
OB SET($obj;"abc";8888)
アンロードして同じレコードを再度カレントレコードにしても、参照が切れているので、カレントレコードは{"abc":8888}にはなりません。同様に
ALL RECORD([Table])
$obj:=[Table]Obj
NEXT RECORD([Table])
PREVIOUS RECORD([Table])
OB SET($obj;"abc";8888)
としてもレコードは変化しません。
ALL RECORD([Table])
SELECTION TO ARRAY([Table]Obj;$aObj)
というように、カレントセレクションをオブジェクト配列にコピーした場合、カレントレコードが自動的にアンロードされてしまいますので、レコードとの参照は切れて独自のインスタンスを保持することとなります。
| 固定リンク
| コメント (0)
| トラックバック (0)