First steps towards introducing a dependency injection framework.

- Add PHP League's Container package via Composer.
- Add an ObjectContainer class that encapsulates all the configuration
  and insulates the codebase from the concrete DI engine used.
- Add an improved ReflectionContainer class that will allow to
  register individual classes as singletons while autowiring.
- Use ObjectContainer to resolve the WooCommerce class, everything
  instantiated with "new" inside it, and all singletons that are
  usually obtained via WC() function.
- Introduce the CustomerProvider class.
- Introduce a service provider to resolve WC_Queue_Interface,
  this replaces the WC_Queue class.
- Mark as obsolete all the replaced "instance()" methods,
  and the entire WC_Queue class.
This commit is contained in:
Nestor Soriano 2020-06-09 12:53:46 +02:00
parent 86da271e6e
commit 312383ae47
13 changed files with 589 additions and 53 deletions

View File

@ -11,6 +11,7 @@
"automattic/jetpack-autoloader": "^1.7.0",
"automattic/jetpack-constants": "^1.1",
"composer/installers": "1.7.0",
"league/container": "^3.3",
"maxmind-db/reader": "1.6.0",
"pelago/emogrifier": "^3.1",
"woocommerce/action-scheduler": "3.1.6",

125
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "313a6737a05bfc27777a05bc22bb7bbe",
"content-hash": "bf5045f466411cb446cbe44074fd7b0f",
"packages": [
{
"name": "automattic/jetpack-autoloader",
@ -195,6 +195,78 @@
],
"time": "2019-08-12T15:00:31+00:00"
},
{
"name": "league/container",
"version": "3.3.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/container.git",
"reference": "93238f74ff5964aee27a78508cdfbdba1cd338f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/container/zipball/93238f74ff5964aee27a78508cdfbdba1cd338f6",
"reference": "93238f74ff5964aee27a78508cdfbdba1cd338f6",
"shasum": ""
},
"require": {
"php": "^7.0",
"psr/container": "^1.0"
},
"provide": {
"psr/container-implementation": "^1.0"
},
"replace": {
"orno/di": "~2.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0",
"squizlabs/php_codesniffer": "^3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-3.x": "3.x-dev",
"dev-2.x": "2.x-dev",
"dev-1.x": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"League\\Container\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Phil Bennett",
"email": "philipobenito@gmail.com",
"homepage": "http://www.philipobenito.com",
"role": "Developer"
}
],
"description": "A fast and intuitive dependency injection container.",
"homepage": "https://github.com/thephpleague/container",
"keywords": [
"container",
"dependency",
"di",
"injection",
"league",
"provider",
"service"
],
"funding": [
{
"url": "https://github.com/philipobenito",
"type": "github"
}
],
"time": "2020-05-18T08:20:23+00:00"
},
{
"name": "maxmind-db/reader",
"version": "v1.6.0",
@ -329,6 +401,55 @@
],
"time": "2019-12-26T19:37:31+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
"homepage": "https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"time": "2017-02-14T16:28:37+00:00"
},
{
"name": "symfony/css-selector",
"version": "v3.4.42",
@ -2521,7 +2642,7 @@
"polyfill",
"portable"
],
"time": "2020-07-14T12:35:20+00:00"
"time": "2020-05-08T16:50:20+00:00"
},
{
"name": "theseer/tokenizer",

View File

@ -8,6 +8,8 @@
* @version 3.4.0
*/
use Automattic\WooCommerce\Tools\DependencyManagement\ObjectContainer;
defined( 'ABSPATH' ) || exit;
/**
@ -19,6 +21,8 @@ class WC_Checkout {
* The single instance of the class.
*
* @var WC_Checkout|null
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
protected static $instance = null;
@ -49,19 +53,23 @@ class WC_Checkout {
* @since 2.1
* @static
* @return WC_Checkout Main instance
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
return self::$instance = ObjectContainer::get_instance_of( __CLASS__ );
}
// Hook in actions once.
add_action( 'woocommerce_checkout_billing', array( self::$instance, 'checkout_form_billing' ) );
add_action( 'woocommerce_checkout_shipping', array( self::$instance, 'checkout_form_shipping' ) );
/**
* Class constructor, hooks the appropriate actions.
*/
public function __construct() {
// Hook in actions once.
add_action( 'woocommerce_checkout_billing', array( $this, 'checkout_form_billing' ) );
add_action( 'woocommerce_checkout_shipping', array( $this, 'checkout_form_shipping' ) );
// woocommerce_checkout_init action is ran once when the class is first constructed.
do_action( 'woocommerce_checkout_init', self::$instance );
}
return self::$instance;
// woocommerce_checkout_init action is ran once when the class is first constructed.
do_action( 'woocommerce_checkout_init', $this );
}
/**

View File

@ -9,6 +9,7 @@
*/
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Tools\DependencyManagement\ObjectContainer;
defined( 'ABSPATH' ) || exit;
@ -28,6 +29,8 @@ class WC_Emails {
* The single instance of the class
*
* @var WC_Emails
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
protected static $_instance = null;
@ -46,12 +49,11 @@ class WC_Emails {
* @since 2.1
* @static
* @return WC_Emails Main instance
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
return self::$_instance = ObjectContainer::get_instance_of( __CLASS__ );
}
/**

View File

@ -8,6 +8,8 @@
* @package WooCommerce/Classes/Payment
*/
use Automattic\WooCommerce\Tools\DependencyManagement\ObjectContainer;
defined( 'ABSPATH' ) || exit;
/**
@ -27,6 +29,8 @@ class WC_Payment_Gateways {
*
* @var WC_Payment_Gateways
* @since 2.1.0
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
protected static $_instance = null;
@ -37,12 +41,11 @@ class WC_Payment_Gateways {
*
* @since 2.1
* @return WC_Payment_Gateways Main instance
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
return self::$_instance = ObjectContainer::get_instance_of( __CLASS__ );
}
/**

View File

@ -9,6 +9,7 @@
*/
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Tools\DependencyManagement\ObjectContainer;
if ( ! defined( 'ABSPATH' ) ) {
exit;
@ -52,6 +53,8 @@ class WC_Shipping {
*
* @var WC_Shipping
* @since 2.1
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
protected static $_instance = null;
@ -62,12 +65,11 @@ class WC_Shipping {
*
* @since 2.1
* @return WC_Shipping Main instance
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
return self::$_instance = ObjectContainer::get_instance_of( __CLASS__ );
}
/**

View File

@ -8,6 +8,9 @@
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Tools\DependencyManagement\ObjectContainer;
use Automattic\WooCommerce\Providers\CustomerProvider;
/**
* Main WooCommerce Class.
*
@ -36,6 +39,8 @@ final class WooCommerce {
*
* @var WooCommerce
* @since 2.1
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
protected static $_instance = null;
@ -109,6 +114,20 @@ final class WooCommerce {
*/
public $deprecated_hook_handlers = array();
/**
* The container used for dependency injection.
*
* @var ObjectContainer
*/
private $container;
/**
* The instance of CustomerProvider to use.
*
* @var CustomerProvider
*/
private $customer_provider;
/**
* Main WooCommerce Instance.
*
@ -118,12 +137,11 @@ final class WooCommerce {
* @static
* @see WC()
* @return WooCommerce - Main instance.
*
* @deprecated 4.3.0 Use dependency injection instead, see the ObjectContainer class.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
return self::$_instance = ObjectContainer::get_instance_of( __CLASS__ );
}
/**
@ -159,7 +177,10 @@ final class WooCommerce {
/**
* WooCommerce Constructor.
*/
public function __construct() {
public function __construct( ObjectContainer $container, CustomerProvider $customer_provider ) {
$this->container = $container;
$this->customer_provider = $customer_provider;
$this->define_constants();
$this->define_tables();
$this->includes();
@ -477,8 +498,8 @@ final class WooCommerce {
}
$this->theme_support_includes();
$this->query = new WC_Query();
$this->api = new WC_API();
$this->query = $this->container->get( WC_Query::class );
$this->api = $this->container->get( WC_API::class );
$this->api->init();
}
@ -560,13 +581,13 @@ final class WooCommerce {
$this->load_plugin_textdomain();
// Load class instances.
$this->product_factory = new WC_Product_Factory();
$this->order_factory = new WC_Order_Factory();
$this->countries = new WC_Countries();
$this->integrations = new WC_Integrations();
$this->structured_data = new WC_Structured_Data();
$this->deprecated_hook_handlers['actions'] = new WC_Deprecated_Action_Hooks();
$this->deprecated_hook_handlers['filters'] = new WC_Deprecated_Filter_Hooks();
$this->product_factory = $this->container->get( WC_Product_Factory::class );
$this->order_factory = $this->container->get( WC_Order_Factory::class );
$this->countries = $this->container->get( WC_Countries::class );
$this->integrations = $this->container->get( WC_Integrations::class );
$this->structured_data = $this->container->get( WC_Structured_Data::class );
$this->deprecated_hook_handlers['actions'] = $this->container->get( WC_Deprecated_Action_Hooks::class );
$this->deprecated_hook_handlers['filters'] = $this->container->get( WC_Deprecated_Filter_Hooks::class );
// Classes/actions loaded for the frontend and for ajax requests.
if ( $this->is_request( 'frontend' ) ) {
@ -754,12 +775,12 @@ final class WooCommerce {
public function initialize_cart() {
// Cart needs customer info.
if ( is_null( $this->customer ) || ! $this->customer instanceof WC_Customer ) {
$this->customer = new WC_Customer( get_current_user_id(), true );
$this->customer = $this->customer_provider->get_logged_in_customer();
// Customer should be saved during shutdown.
add_action( 'shutdown', array( $this->customer, 'save' ), 10 );
}
if ( is_null( $this->cart ) || ! $this->cart instanceof WC_Cart ) {
$this->cart = new WC_Cart();
$this->cart = $this->container->get( WC_Cart::class );
}
}
@ -773,7 +794,7 @@ final class WooCommerce {
// Session class, handles session data for users - can be overwritten if custom handler is needed.
$session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
if ( is_null( $this->session ) || ! $this->session instanceof $session_class ) {
$this->session = new $session_class();
$this->session = $this->container->get( $session_class );
$this->session->init();
}
}
@ -815,7 +836,7 @@ final class WooCommerce {
* @return WC_Queue_Interface
*/
public function queue() {
return WC_Queue::instance();
return $this->container->get( WC_Queue_Interface::class );
}
/**
@ -824,7 +845,7 @@ final class WooCommerce {
* @return WC_Checkout
*/
public function checkout() {
return WC_Checkout::instance();
return $this->container->get( WC_Checkout::class );
}
/**
@ -833,7 +854,7 @@ final class WooCommerce {
* @return WC_Payment_Gateways
*/
public function payment_gateways() {
return WC_Payment_Gateways::instance();
return $this->container->get( WC_Payment_Gateways::class );
}
/**
@ -842,7 +863,7 @@ final class WooCommerce {
* @return WC_Shipping
*/
public function shipping() {
return WC_Shipping::instance();
return $this->container->get( WC_Shipping::class );
}
/**
@ -851,7 +872,7 @@ final class WooCommerce {
* @return WC_Emails
*/
public function mailer() {
return WC_Emails::instance();
return $this->container->get( WC_Emails::class );
}
/**

View File

@ -6,6 +6,8 @@
* @package WooCommerce/Interface
*/
use Automattic\WooCommerce\Tools\DependencyManagement\ObjectContainer;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
@ -16,6 +18,8 @@ if ( ! defined( 'ABSPATH' ) ) {
* Singleton for managing the WC queue instance.
*
* @version 3.5.0
*
* @deprecated 4.3.0 Use dependency injection instead to get an instance of WC_Query_Interface, see the ObjectContainer class.
*/
class WC_Queue {
@ -39,13 +43,7 @@ class WC_Queue {
* @return WC_Queue_Interface
*/
final public static function instance() {
if ( is_null( self::$instance ) ) {
$class = self::get_class();
self::$instance = new $class();
self::$instance = self::validate_instance( self::$instance );
}
return self::$instance;
return self::$instance = ObjectContainer::get_instance_of( WC_Queue_Interface::class );
}
/**

View File

@ -0,0 +1,36 @@
<?php
/**
* CustomerProvider class file.
*
* @package Automattic\WooCommerce\Providers
*/
namespace Automattic\WooCommerce\Providers;
use \WC_Customer;
/**
* Provides methods to retrieve customer objects.
*/
class CustomerProvider {
/**
* Get a customer object for the currently logged in user.
*
* @return WC_Customer Customer object for the currently logged in user.
*/
public function get_logged_in_customer() {
return new WC_Customer( get_current_user_id(), true );
}
/**
* Get a customer object by id.
*
* @param int $id The id of the customer to retrieve.
*
* @return WC_Customer Customer object for the specified id.
*/
public function get_customer_by_id( int $id ) {
return new WC_Customer( $id );
}
}

View File

@ -0,0 +1,169 @@
<?php
/**
* ObjectContainer class file.
*
* @package Automattic\WooCommerce\Tools\DependencyManagement
*/
namespace Automattic\WooCommerce\Tools\DependencyManagement;
use \League\Container\Container;
use \Automattic\WooCommerce\Tools\DependencyManagement\ReflectionContainer as WooReflectionContainer;
/**
* Dependency injection container for WooCommerce.
*
* This class uses PHP League's `Container` under the hood. A separate container class is used to
* insulate the codebase from the exact DI engine used, and to encapsulate all the class and service provider registrations.
*
* Usage:
*
* - To register new class resolutions:
* - Do it in the `register_classes` method, using the `container` and `reflection_container` class properties.
* In particular, use `reflection_container->share` to register autowiring singletons.
* No extra action is needed to use non-singleton autowiring.
* - Or alternatively, create a new service provider inside the `ServiceProviders` folder and it will be
* automatically registered. Service providers are recommended when instantiating the class is a complex
* or slow process.
*
* - To resolve classes to instances:
* - Ideally you just add your dependency as a typed argument in the class constructor, and it gets resolved
* automatically (via autowiring) when the class is instantiated via the container. This is the preferred approach.
* - If the above is not possible, you can add an argument of type `ObjectContainer` to the class constructor,
* and then use the `get` method of the supplied instance whenever needed.
* - For code outside classes (inside standalone functions) or in static class methods, use
* `ObjectContainer::get_instance_of`.
*
* Note: autowiring means the ability to automatically resolve a class name to an instance of that class via
* `get(TheClass::class)` or by adding a typed argument to class constructors.
*/
final class ObjectContainer {
/**
* The singleton instance of ObjectContainer.
*
* @var ObjectContainer
*/
private static $instance = null;
/**
* The underlying dependency injection engine used.
*
* @var Container
*/
private $container;
/**
* The underlying reflection delegate used for autowiring.
*
* @var ReflectionContainer
*/
private $reflection_container;
/**
* Get the singleton instance of ObjectContainer.
*
* @return ObjectContainer
*/
public static function instance() {
return self::$instance;
}
/**
* Initialize the dependency injection engine and do all the necessary registrations.
*/
public static function init() {
global $wp_actions;
if ( ! function_exists( 'did_action' ) || did_action( 'plugins_loaded' ) ) {
self::_init();
} else {
// TODO: This is a hack to overcome the inability to use the autoloader before plugins have been loaded, remove after https://github.com/Automattic/jetpack/pull/15106 is merged.
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$wp_actions['plugins_loaded'] = 1;
self::_init();
unset( $wp_actions['plugins_loaded'] );
}
}
/**
* Initialize the dependency injection engine and do all the necessary registrations.
*/
public static function _init() {
// Instantiate the underlying container and create the singleton instance of ourselves.
$container = new Container();
self::$instance = new self( $container );
// Register our singleton instance so we're able to resolve ourselves.
$container->add( __CLASS__, self::$instance );
// Register the reflection container to allow autowiring.
self::$instance->reflection_container = new WooReflectionContainer();
$container->delegate( self::$instance->reflection_container );
// Perform any required manual class and service provider registration.
self::$instance->register_classes();
self::$instance->register_service_providers();
}
/**
* Class constructor.
*
* @param Container $container The instance of League\Container\Container to use for dependency injection.
*/
public function __construct( Container $container ) {
$this->container = $container;
}
/**
* Register class resolutions for which default autowiring is not appropriate/enough.
*/
private function register_classes() {
$singletons = array(
\CustomerProvider::class,
\WC_Checkout::class,
\WC_Emails::class,
\WC_Payment_Gateways::class,
\WC_Shipping::class,
\WooCommerce::class,
);
foreach ( $singletons as $class_name ) {
$this->reflection_container->share( $class_name );
}
}
/**
* Register all the service providers inside the ServiceProviders directory.
*/
private function register_service_providers() {
$service_provider_files = array_diff( scandir( __DIR__ . '/ServiceProviders' ), array( '..', '.' ) );
foreach ( $service_provider_files as $file ) {
$filename = pathinfo( $file )['filename'];
$this->container->addServiceProvider( __NAMESPACE__ . "\\ServiceProviders\\$filename" );
}
}
/**
* Resolve an instance of a class.
*
* @param string $class_name Class name to get an instance of.
*
* @return object The resolved object.
*/
public function get( string $class_name ) {
return $this->container->get( $class_name );
}
/**
* Resolve an instance of a class.
*
* @param string $class_name Class name to get an instance of.
*
* @return object The resolved object.
*/
public static function get_instance_of( string $class_name ) {
return self::instance()->get( $class_name );
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace Automattic\WooCommerce\Tools\DependencyManagement;
/**
* The original PHP League's `ReflectionContainer`, used for autowiring, provides an all-or-nothing approach
* for registering singletons: either all the resolved objects are, or none is. This class provides a new `share`
* method that allows to register classes to be resolved as singleton objects even if `cacheResolutions` is disabled.
*
* @package Automattic\WooCommerce\Tools\DependencyManagement
*/
class ReflectionContainer extends \League\Container\ReflectionContainer {
/**
* @var array Names of the classes to always be resolved as singletons.
*/
protected $classes_to_always_cache = array();
/**
* Register a class to be always resolved as a singleton object, even if `cacheResolutions` is disabled.
*
* @param string $class_name The name of the class to register.
*/
public function share( string $class_name ) {
if ( ! in_array( $class_name, $this->classes_to_always_cache, true ) ) {
array_push( $this->classes_to_always_cache, $class_name );
}
}
/**
* {@inheritdoc}
*
* @throws ReflectionException
*/
public function get( $id, array $args = array() ) {
if ( true === $this->cacheResolutions || ! in_array( $id, $this->classes_to_always_cache ) ) {
return parent::get( $id, $args );
}
if ( array_key_exists( $id, $this->cache ) ) {
return $this->cache[ $id ];
}
$resolution = parent::get( $id, $args );
$this->cache[ $id ] = $resolution;
return $resolution;
}
}

View File

@ -0,0 +1,102 @@
<?php
/**
* QueueServiceProvider class file.
*
* @package Automattic\WooCommerce\Tools\DependencyManagement\ServiceProviders
*/
namespace Automattic\WooCommerce\Tools\DependencyManagement\ServiceProviders;
use League\Container\ServiceProvider\AbstractServiceProvider;
use \ReflectionClass;
use \ReflectionException;
use \WC_Action_Queue;
use \WC_Queue_Interface;
/**
* Service provider for WC_Queue_Interface.
*/
class QueueServiceProvider extends AbstractServiceProvider {
/**
* The queue class that will be instantiated unless something different is specified via woocommerce_queue_class filter.
*/
const DEFAULT_QUEUE_CLASS = WC_Action_Queue::class;
/**
* The classes/interfaces that are serviced by this service provider.
*
* @var array
*/
protected $provides = array(
WC_Queue_Interface::class,
);
/**
* Register the function that will create the singleton instance of WC_Queue_Interface.
*/
public function register() {
$container = $this->getContainer();
$container->share(
WC_Queue_Interface::class,
function() {
return $this->get_queue_instance();
}
);
}
/**
* Create a new instance of a class implementing WC_Queue_Interface.
* It will be an instance of {DEFAULT_QUEUE_CLASS} unless something different is specified via woocommerce_queue_class filter.
*
* @return WC_Queue_Interface
*/
private function get_queue_instance() {
if ( ! did_action( 'plugins_loaded' ) ) {
$this->error_bad_timing();
}
$queue_class = apply_filters( 'woocommerce_queue_class', self::DEFAULT_QUEUE_CLASS );
$rc = null;
try {
$rc = new ReflectionClass( $queue_class );
} catch ( ReflectionException $exception ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
// $rc will remain null and this will be enough to detect the error later.
}
if ( is_null( $rc ) || ! $rc->implementsInterface( WC_Queue_Interface::class ) ) {
$this->error_bad_class();
$queue_class = self::DEFAULT_QUEUE_CLASS;
}
return $this->getContainer()->get( $queue_class );
}
/**
* Throw a "plugins not loaded" notice.
*/
private function error_bad_timing() {
wc_doing_it_wrong(
__FUNCTION__,
__( 'Queue instance should not be obtained before plugins_loaded.', 'woocommerce' ),
'3.5.0'
);
}
/**
* Throw a "invalid class name" notice.
*/
private function error_bad_class() {
wc_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %1$s: Interface name, %2$s: Default class name */
__( 'The class attached to the "woocommerce_queue_class" filter is invalid or does not implement the %1$s interface. The default %2$s class will be used instead.', 'woocommerce' ),
WC_Queue_Interface::class,
self::DEFAULT_QUEUE_CLASS
),
'3.5.0'
);
}
}

View File

@ -16,6 +16,8 @@
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Tools\DependencyManagement\ObjectContainer;
if ( ! defined( 'WC_PLUGIN_FILE' ) ) {
define( 'WC_PLUGIN_FILE', __FILE__ );
}
@ -29,11 +31,33 @@ if ( ! \Automattic\WooCommerce\Autoloader::init() ) {
}
\Automattic\WooCommerce\Packages::init();
// Define a simple autoloader for the object container to work.
// Function grabbed from https://container.thephpleague.com/3.x
spl_autoload_register(
function ( $class ) {
$prefix = 'Automattic\\WooCommerce\\';
$base_dir = __DIR__ . '/src/';
$len = strlen( $prefix );
if ( strncmp( $prefix, $class, $len ) !== 0 ) {
// no, move to the next registered autoloader
return;
}
$relative_class = substr( $class, $len );
$file = $base_dir . str_replace( '\\', '/', $relative_class ) . '.php';
if ( file_exists( $file ) ) {
require $file;
}
}
);
// Include the main WooCommerce class.
if ( ! class_exists( 'WooCommerce', false ) ) {
include_once dirname( WC_PLUGIN_FILE ) . '/includes/class-woocommerce.php';
}
// Initialize dependency injection.
ObjectContainer::init();
/**
* Returns the main instance of WC.
*
@ -41,7 +65,7 @@ if ( ! class_exists( 'WooCommerce', false ) ) {
* @return WooCommerce
*/
function WC() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
return WooCommerce::instance();
return ObjectContainer::get_instance_of( WooCommerce::class );
}
// Global for backwards compatibility.