brightnucleus/static-facade

Abstract static Facade class to wrap around shared object instances for convenient access.

v0.1.1 2016-10-25 11:25 UTC

This package is auto-updated.

Last update: 2024-03-16 05:31:17 UTC


README

Latest Stable Version Total Downloads Latest Unstable Version License

Abstract static Facade class to wrap around shared object instances for convenient access.

Table Of Contents

Installation

The best way to use this package is through Composer:

composer require brightnucleus/static-facade

Basic Usage

To create a static Facade, you can either extend the StaticFacade class or use the StaticFacadeTrait, depending on whether you need to extend an existing class or not.

Such a static Facade will then forward any static method calls it gets to the instance of the object it is wrapping as a dynamic method call.

As an example, let's say you have a UserRepository class to fetch users from. If you can't have that shared instance just be injected through the constructor (which would avoid a static coupling), you would normally either have a way of getting the shared instance through a static call (UserRepository::getInstance()) or have a Service Locator to get the shared instance (Services::get('UserRepository')). This produces cumbersome code, as every interaction with such a class consists of two separate steps.

To make this more convenient, you can provide a static Facade that abstracts away the fetching of the shared instance.

Example:

// Without a static Facade.
$userRepository = Services::get( 'UserRepository' );
$user = $userRepository->find( $userID );

// With a static Facade.
$user = UserRepository::find( $userID );

Note: This creates a tight coupling within the consuming code to the static Facade itself. This is great for getting around limitations in legacy code, and is preferable to coupling your code to the actual class being used, as you have another layer abstraction and can modify/replace the actual class as needed. However, you should always prefer having your dependencies be injected at runtime without creating such a tight coupling.

Extending The StaticFacade Class

You would typically extend the StaticFacade class if you don't need to have your Facade extend another existing class.

Example:

<?php declare(strict_types = 1);

namespace Example\Project;

use BrightNucleus\StaticFacade\StaticFacade;

class UserRepository extends StaticFacade
{
    
    protected static function getFacadeInstance()
    {
        // Return the shared instance of the object you are wrapping here. 
    }
}

Using The StaticFacadeTrait Trait

If your Facade already extends another class, you cannot use the StaticFacade class, as PHP does not allow for multiple inheritance. In this case, you can make use of the StaticFacadeTrait that provides the same functionality.

Example:

<?php declare(strict_types = 1);

namespace Example\Project;

use BrightNucleus\StaticFacade\StaticFacadeTrait;

class UserRepository extends AbstractRepository
{
    
    use StaticFacadeTrait;

    protected static function getFacadeInstance()
    {
        // Return the shared instance of the object you are wrapping here. 
    }
}

Exception Thrown On Missing Method

By default, a BrightNucleus\Exception\BadMethodCallException with a detailed message is thrown when an unknown method is called through the Facade.

To provide custom exceptions, you can override the getFacadeException method, that has the following signature:

protected static function getFacadeException(string $method, array $arguments) : Exception

Adding Methods Directly To The Facade

By default, the static Facade will now just work, and forward any method calls to its wrapped object dynamically.

However, you can always directly add stubs to the Facade. This might make sense if you're using the Facade a lot, as the automagic method of forwarding the calls is slower than a direct call, and it is also missing the necessary hints for your IDE to make any sense of it.

To use direct calls, just add the matching static methods, and forward the arguments to the dynamic method no the object's instance, like in the following example:

public static function find(int $userID) {
    return Services::get('UserRepository')
                   ->find($userID);
}

Contributing

All feedback / bug reports / pull requests are welcome.

License

Copyright (c) 2016 Alain Schlesser, Bright Nucleus

This code is licensed under the MIT License.