@@ -54,7 +54,7 @@ public static function defaultHelpers(): array
5454 $ context = $ context ($ options ->scope );
5555 }
5656 if (!is_iterable ($ context )) {
57- $ context = [];
57+ $ context = is_object ( $ context ) ? get_object_vars ( $ context ) : [];
5858 }
5959 return $ options ->iterate ($ context );
6060 },
@@ -109,7 +109,7 @@ public static function defaultHelpers(): array
109109 }
110110
111111 /**
112- * Strict-mode key lookup: throw if $base is not an array or $key is absent .
112+ * Strict-mode key lookup: throw if $key is absent from $base .
113113 * Unlike the null-coalescing pattern, this allows null values when the key exists.
114114 */
115115 public static function strictLookup (mixed $ base , string $ key ): mixed
@@ -118,6 +118,8 @@ public static function strictLookup(mixed $base, string $key): mixed
118118 if (array_key_exists ($ key , $ base )) {
119119 return $ base [$ key ];
120120 }
121+ } elseif (is_object ($ base ) && property_exists ($ base , $ key )) {
122+ return $ base ->$ key ;
121123 }
122124 $ desc = match (true ) {
123125 is_bool ($ base ) => $ base ? 'true ' : 'false ' ,
@@ -139,20 +141,40 @@ public static function nullCheck(mixed $base, string $key): mixed
139141 if ($ base === null ) {
140142 throw new \ErrorException ("Cannot access property \"$ key \" on null " );
141143 }
142- return is_array ($ base ) ? ($ base [$ key ] ?? null ) : null ;
144+ if (is_array ($ base )) {
145+ return $ base [$ key ] ?? null ;
146+ }
147+ if (is_object ($ base )) {
148+ return $ base ->$ key ?? null ;
149+ }
150+ return null ;
151+ }
152+
153+ /**
154+ * Default key/property lookup for normal mode: $base[$key] for arrays, $base->$key for objects.
155+ */
156+ public static function prop (mixed $ base , string $ key ): mixed
157+ {
158+ if (is_array ($ base )) {
159+ return $ base [$ key ] ?? null ;
160+ }
161+ if (is_object ($ base )) {
162+ return $ base ->$ key ?? null ;
163+ }
164+ return null ;
143165 }
144166
145167 /**
146168 * Terminal .length lookup: returns count() for arrays (since PHP arrays have no native .length
147- * property), an explicit 'length' key if present, or null for non-array bases.
148- * When $strict is true, throws for any non-array base, mirroring HBS.js strict-mode behavior .
169+ * property), an explicit 'length' key if present, or null for non-array/non-object bases.
170+ * When $strict is true, throws for objects without a 'length' property and for all scalar/null bases .
149171 */
150172 public static function lookupLength (mixed $ base , bool $ strict = false ): mixed
151173 {
152174 if (is_array ($ base )) {
153175 return array_key_exists ('length ' , $ base ) ? $ base ['length ' ] : count ($ base );
154176 }
155- return $ strict ? self ::strictLookup ($ base , 'length ' ) : null ;
177+ return $ strict ? self ::strictLookup ($ base , 'length ' ) : self :: prop ( $ base , ' length ' ) ;
156178 }
157179
158180 /**
@@ -209,7 +231,7 @@ public static function lambda(mixed $v): mixed
209231 */
210232 public static function lookupValue (mixed &$ _this , string $ name , bool $ strict = false ): mixed
211233 {
212- $ v = $ strict ? self ::strictLookup ($ _this , $ name ) : ($ _this[ $ name] ?? null );
234+ $ v = $ strict ? self ::strictLookup ($ _this , $ name ) : self :: prop ($ _this, $ name );
213235 return $ v instanceof Closure ? $ v ($ _this ) : $ v ;
214236 }
215237
@@ -230,7 +252,7 @@ public static function invokeAmbiguous(RuntimeContext $cx, string $name, mixed &
230252 } elseif ($ strict ) {
231253 $ value = self ::strictLookup ($ _this , $ name );
232254 } else {
233- $ value = $ assumeObjects ? self ::nullCheck ($ _this , $ name ) : ($ _this[ $ name] ?? null );
255+ $ value = $ assumeObjects ? self ::nullCheck ($ _this , $ name ) : self :: prop ($ _this, $ name );
234256 }
235257 if (!$ strict ) {
236258 $ value ??= $ cx ->helpers ['helperMissing ' ];
@@ -253,11 +275,17 @@ public static function compatLookup(RuntimeContext $cx, mixed $in, string $name,
253275 if (is_array ($ in ) && array_key_exists ($ name , $ in )) {
254276 return $ in [$ name ];
255277 }
278+ if (is_object ($ in ) && property_exists ($ in , $ name )) {
279+ return $ in ->$ name ;
280+ }
256281 for ($ i = count ($ cx ->depths ) - 1 ; $ i >= 0 ; $ i --) {
257282 $ ctx = $ cx ->depths [$ i ];
258283 if (is_array ($ ctx ) && array_key_exists ($ name , $ ctx )) {
259284 return $ ctx [$ name ];
260285 }
286+ if (is_object ($ ctx ) && property_exists ($ ctx , $ name )) {
287+ return $ ctx ->$ name ;
288+ }
261289 }
262290 return $ strict ? self ::strictLookup (null , $ name ) : null ;
263291 }
0 commit comments