DO wwDynamic DO wwJsonSerializer CLEAR loCust = CREATEOBJECT("TestClass") loItem = CREATEOBJECT("wwDynamic",loCust) *loItem = CREATEOBJECT("wwDynamic") && create new EMPTY top level instance ? loItem.Class loItem.Bogus = "This is bogus" loItem.Entered = DATETIME() ? loItem.Bogus ? loItem.Entered WITH loItem.Child .Bogus2 = "Child Bogus" .Entered2 = DATETIME() ? .Bogus2 ? .Entered2 ENDWITH *** Access original object members ? loItem.cFirstName ? loItem.cLastName ? loItem.GetFullname() *** Create new children several levels deep loItem.SecondChild.ThirdChild.SecondChildName = "Frank" loItem.SecondChild.ThirdChild.SecondChildEntered = DATETIME() *** Serialize - wwJsonSerializer has custom logic to deal with wwDynamic loSer = CREATEOBJECT("wwJsonSerializer") lcJson = loSer.Serialize(loItem,.T.) ? lcJson _cliptext = lcJson *** Base class to pass in DEFINE CLASS TestClass as Custom cFirstName = "Rick" cLastName = "Strahl" FUNCTION GetFullName() RETURN this.cFirstname + " " + this.cLastname ENDDEFINE ************************************************************* DEFINE CLASS wwDynamic AS RELATION ************************************************************* *: original Author: Marco Plaza, 2018 @vfp2nfox *: modified by: Rick Strahl ************************************************************* __oReference = null *** Intercept access to unknown properties and create FUNCTION THIS_Access(lcPropertyOrMethod) If Lower(lcPropertyOrMethod) == "__oreference" OR ; Pemstatus(this,lcPropertyOrMethod,5) RETURN this Endif If !Pemstatus(this.__oReference,lcPropertyOrMethod,5) AddProperty(this.__oReference,lcPropertyOrMethod,Createobject('wwDynamic')) ENDIF RETURN this.__oReference ENDFUNC ************************************************************************ * Init **************************************** *** Function: *** Assume: *** Pass: *** Return: ************************************************************************ FUNCTION Init(loBaseType) IF !VARTYPE(loBaseType) = "O" this.__oReference = CREATEOBJECT("Empty") ELSE this.__oReference = loBaseType ENDIF ENDFUNC * Init ENDDEFINE *EOC wwDynamicwhich produces:
{ "bogus": "This is bogus", "cfirstname": "Rick", "child": { "bogus2": "Child Bogus", "entered2": "2018-11-26T22:21:48Z" }, "clastname": "Strahl", "entered": "2018-11-26T22:21:48Z", "name": "Testclass", "secondchild": { "thirdchild": { "secondchildentered": "2018-11-26T22:21:48Z", "secondchildname": "Frank" } } }The main difference here is that you have the raw child structure whereas I'm Ok with the extra reference and dealing with the Serialization explicitly. From a usability POV though this feels a lot cleaner to me than having to inject a function everywhere I need a new object reference.
> >*---------------------------------------------- >* Create a deep object structure at once: >*---------------------------------------------- >* >* instead of: >* >* oCust = create('empty') >* addproperty(oCust,'oInfo',create('empty') >* addproperty(oCust.oInfo,'address',create('empty') >* addproperty(oCust.oInfo.address.billing,'phone',create('empty') >* oCust.oInfo.address.billing.phone = 2358811 >* >*---------------------------------------------------------------------- >* using _( ) : >* > >oCust = createObject('empty') > >with _( m.oCust ,'.info.address.billing.phone') > .number = 2358811 >endwith > >? 'm.oCust.info.address.billing.phone.number:' >?? m.oCust.info.address.billing.phone.number > >