*/ private $instances = []; /** @var array */ private $section_feature_instances = []; /** * Construct and retain one enabled module under its canonical ID. * * Sections choose which modules they own, while this loader remains the * sole construction authority. Repeated calls return the same instance. * * @param string $module_id Canonical module ID. * * @return Base_Module|null The constructed (or previously retained) * instance, or null when the module is * disabled, unavailable, or its runtime target * does not resolve to a valid Base_Module subclass. */ public function boot_module( string $module_id ): ?Base_Module { if ( isset( $this->instances[ $module_id ] ) ) { return $this->instances[ $module_id ]; } $target = Module_Registry::get_runtime_target( $module_id ); if ( ! Module_Registry::can_run( $module_id ) || ! is_string( $target ) || ! class_exists( $target ) || ! is_subclass_of( $target, Base_Module::class ) ) { return null; } $this->instances[ $module_id ] = new $target(); return $this->instances[ $module_id ]; } /** * Construct and retain one enabled `SECTION_FEATURE` capability's * optional supporting class under its canonical ID. * * `SECTION_FEATURE` capabilities remain owned by their Section rather * than becoming ordinary loader-constructed `MODULE`s; a `SECTION_FEATURE` * class is not a `Base_Module` and carries no settings/asset contract, so * it is kept in its own instance cache and returned as a plain object. * Repeated calls return the same instance. * * @param string $module_id Canonical SECTION_FEATURE capability ID. * * @return object|null The constructed (or previously retained) * instance, or null when the capability is * disabled, unavailable, or its runtime target * class does not exist. */ public function boot_section_feature( string $module_id ): ?object { if ( isset( $this->section_feature_instances[ $module_id ] ) ) { return $this->section_feature_instances[ $module_id ]; } $target = Module_Registry::get_runtime_target( $module_id ); if ( ! Module_Registry::can_run_section_feature( $module_id ) || ! is_string( $target ) || ! class_exists( $target ) ) { return null; } $this->section_feature_instances[ $module_id ] = new $target(); return $this->section_feature_instances[ $module_id ]; } /** * Get an already-retained module instance without booting it. * * @param string $module_id Canonical module ID. * * @return Base_Module|null The retained instance, or null if the * module has not been booted this request. */ public function get( string $module_id ): ?Base_Module { return $this->instances[ $module_id ] ?? null; } /** * Get an already-retained SECTION_FEATURE supporting-class instance * without constructing it. * * @param string $module_id Canonical SECTION_FEATURE capability ID. * * @return object|null The retained instance, or null if it has not * been constructed this request. */ public function get_section_feature( string $module_id ): ?object { return $this->section_feature_instances[ $module_id ] ?? null; } }