From feee1fb25e74475d40242870a6a333b7ad56b693 Mon Sep 17 00:00:00 2001 From: Huzaifa Al Mesbah Date: Fri, 16 Oct 2026 16:53:28 +0600 Subject: [PATCH 1/2] Framework: Store one Factory instance per subclass `Framework\Factory::get_instance()` stored the instance in `self::$instance` on the abstract base class, so every factory subclass returned whichever factory was created first. Store instances in a `static::$instances` map keyed by `static::class`, fix the `get_instance()` return type in the docblock, and add unit tests. Fixes #613. --- includes/framework/class-factory.php | 17 ++++---- .../phpunit/tests/framework/test-factory.php | 41 +++++++++++++++++++ 2 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 tests/phpunit/tests/framework/test-factory.php diff --git a/includes/framework/class-factory.php b/includes/framework/class-factory.php index 02c66b5e..eec296ac 100644 --- a/includes/framework/class-factory.php +++ b/includes/framework/class-factory.php @@ -15,11 +15,11 @@ abstract class Factory { /** - * Container for the main instance of the class. + * Container for the main instance of each factory subclass, keyed by class name. * - * @property ?Model + * @var array, static> */ - protected static $instance = null; + protected static $instances = array(); /** * Instantiates a model object. @@ -33,15 +33,16 @@ abstract public function make( $args ); /** * Utility method to retrieve the main instance of the class. * - * The instance will be created if it does not exist yet. + * The instance will be created if it does not exist yet. Each subclass + * has its own instance. * - * @return Model The main instance. + * @return static The main instance. */ public static function get_instance() { - if ( null === self::$instance ) { - self::$instance = new static(); + if ( ! isset( static::$instances[ static::class ] ) ) { + static::$instances[ static::class ] = new static(); } - return self::$instance; + return static::$instances[ static::class ]; } } diff --git a/tests/phpunit/tests/framework/test-factory.php b/tests/phpunit/tests/framework/test-factory.php new file mode 100644 index 00000000..9f4ba4cb --- /dev/null +++ b/tests/phpunit/tests/framework/test-factory.php @@ -0,0 +1,41 @@ +assertInstanceOf( Factory\Message::class, Factory\Message::get_instance() ); + $this->assertInstanceOf( Factory\Notification::class, Factory\Notification::get_instance() ); + $this->assertInstanceOf( Factory\Subscription::class, Factory\Subscription::get_instance() ); + } + + /** + * Should not share one instance across factory subclasses. + */ + public function test_get_instance_is_distinct_per_subclass() { + $message = Factory\Message::get_instance(); + $notification = Factory\Notification::get_instance(); + $subscription = Factory\Subscription::get_instance(); + + $this->assertNotSame( $message, $notification ); + $this->assertNotSame( $message, $subscription ); + $this->assertNotSame( $notification, $subscription ); + } + + /** + * Should return the same instance on repeated calls for the same subclass. + */ + public function test_get_instance_is_singleton_per_subclass() { + $this->assertSame( Factory\Message::get_instance(), Factory\Message::get_instance() ); + $this->assertSame( Factory\Notification::get_instance(), Factory\Notification::get_instance() ); + } +} From 5a9df299cea0eec95788cf45beedb7880907f574 Mon Sep 17 00:00:00 2001 From: Huzaifa Al Mesbah Date: Sat, 31 Oct 2026 23:22:51 +0600 Subject: [PATCH 2/2] Framework: Keep all Factory instances on the base class Use self::$instances so every instance stays in the one array on Factory, even if a subclass declares its own $instances property. Also check Factory\Subscription in the singleton test. --- includes/framework/class-factory.php | 6 +++--- tests/phpunit/tests/framework/test-factory.php | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/includes/framework/class-factory.php b/includes/framework/class-factory.php index eec296ac..6d5588f6 100644 --- a/includes/framework/class-factory.php +++ b/includes/framework/class-factory.php @@ -39,10 +39,10 @@ abstract public function make( $args ); * @return static The main instance. */ public static function get_instance() { - if ( ! isset( static::$instances[ static::class ] ) ) { - static::$instances[ static::class ] = new static(); + if ( ! isset( self::$instances[ static::class ] ) ) { + self::$instances[ static::class ] = new static(); } - return static::$instances[ static::class ]; + return self::$instances[ static::class ]; } } diff --git a/tests/phpunit/tests/framework/test-factory.php b/tests/phpunit/tests/framework/test-factory.php index 9f4ba4cb..b4e7b651 100644 --- a/tests/phpunit/tests/framework/test-factory.php +++ b/tests/phpunit/tests/framework/test-factory.php @@ -37,5 +37,6 @@ public function test_get_instance_is_distinct_per_subclass() { public function test_get_instance_is_singleton_per_subclass() { $this->assertSame( Factory\Message::get_instance(), Factory\Message::get_instance() ); $this->assertSame( Factory\Notification::get_instance(), Factory\Notification::get_instance() ); + $this->assertSame( Factory\Subscription::get_instance(), Factory\Subscription::get_instance() ); } }