@@ -244,6 +244,55 @@ public function testIsInstanceOf()
244244 $ this ->assertFalse ($ subject2 ->isClassInstanceOf (ExampleExtendableInterface::class));
245245 $ this ->assertTrue ($ subject3 ->isClassInstanceOf (ExampleExtendableInterface::class));
246246 }
247+
248+ public function testDynamicExtendOverridesMethod ()
249+ {
250+ $ subject = new ExtendableTestExampleExtendableClass ;
251+ $ this ->assertEquals ('foo ' , $ subject ->getFoo ());
252+
253+ $ subject ->extendClassWith ('ExtendableTestExampleBehaviorClass2 ' );
254+ $ this ->assertEquals ('bar ' , $ subject ->getFoo ());
255+ }
256+
257+ public function testDynamicExtendOverrideAsExtension ()
258+ {
259+ $ subject = new ExtendableTestExampleExtendableClass ;
260+ $ subject ->extendClassWith ('ExtendableTestExampleBehaviorClass2 ' );
261+
262+ // Default call resolves to the last registered behavior
263+ $ this ->assertEquals ('bar ' , $ subject ->getFoo ());
264+
265+ // asExtension can still reach the original behavior
266+ $ this ->assertEquals ('foo ' , $ subject ->asExtension ('ExtendableTestExampleBehaviorClass1 ' )->getFoo ());
267+ $ this ->assertEquals ('bar ' , $ subject ->asExtension ('ExtendableTestExampleBehaviorClass2 ' )->getFoo ());
268+ }
269+
270+ public function testMultipleBehaviorsMethodPriority ()
271+ {
272+ $ subject = new ExtendableTestExampleExtendableMultiBehaviorClass ;
273+
274+ // BehaviorClass2 is last in $implement, so it wins
275+ $ this ->assertEquals ('bar ' , $ subject ->getFoo ());
276+
277+ // Both behaviors are still accessible directly
278+ $ this ->assertEquals ('foo ' , $ subject ->asExtension ('ExtendableTestExampleBehaviorClass1 ' )->getFoo ());
279+ $ this ->assertEquals ('bar ' , $ subject ->asExtension ('ExtendableTestExampleBehaviorClass2 ' )->getFoo ());
280+ }
281+
282+ public function testDynamicExtendOverridesImplementMethod ()
283+ {
284+ $ subject = new ExtendableTestExampleExtendableMultiBehaviorClass ;
285+ $ this ->assertEquals ('bar ' , $ subject ->getFoo ());
286+
287+ // Dynamic extension overrides both implemented behaviors
288+ $ subject ->extendClassWith ('ExtendableTestExampleBehaviorClass3 ' );
289+ $ this ->assertEquals ('baz ' , $ subject ->getFoo ());
290+
291+ // All three behaviors remain accessible via asExtension
292+ $ this ->assertEquals ('foo ' , $ subject ->asExtension ('ExtendableTestExampleBehaviorClass1 ' )->getFoo ());
293+ $ this ->assertEquals ('bar ' , $ subject ->asExtension ('ExtendableTestExampleBehaviorClass2 ' )->getFoo ());
294+ $ this ->assertEquals ('baz ' , $ subject ->asExtension ('ExtendableTestExampleBehaviorClass3 ' )->getFoo ());
295+ }
247296}
248297
249298//
@@ -419,6 +468,25 @@ public function getProtectedFooAttribute()
419468 }
420469}
421470
471+ class ExtendableTestExampleBehaviorClass3 extends ExtensionBase
472+ {
473+ public function getFoo ()
474+ {
475+ return 'baz ' ;
476+ }
477+ }
478+
479+ /*
480+ * Example class with multiple behaviors that define the same method
481+ */
482+ class ExtendableTestExampleExtendableMultiBehaviorClass extends Extendable
483+ {
484+ public $ implement = [
485+ 'ExtendableTestExampleBehaviorClass1 ' ,
486+ 'ExtendableTestExampleBehaviorClass2 ' ,
487+ ];
488+ }
489+
422490/*
423491 * Add namespaced aliases for dot notation test
424492 */
0 commit comments