XStatic is a PHP library for enabling static proxy interfaces

Related tags

Frameworks xstatic
Overview

This is no longer supported

Please consider using ReStatic instead.

XStatic

No Maintenance Intended

XStatic is a PHP library for enabling static proxy interfaces—similar to Laravel 4+ "Facades"—but with any PHP project. XStatic was created by Jeremy Lindblom.

ATTENTION: Please consider using ReStatic, a maintained fork of this library. XStatic is no longer actively supported.

Introduction (Q&A)

Facades? Static Proxies? Isn't using static methods considered a bad practice?

Using static methods and classes makes your code harder to test. This is because your code becomes tightly coupled to the class being referenced statically, and mocking static methods for unit tests is difficult. For this and other reasons, using static methods is generally discouraged by object-oriented programming (OOP) experts. Generally, techniques involving design patterns like Service Locator and Dependency Injection (DI) are preferred for managing object dependencies and composition.

But... using static methods is really easy.

True, and PHP developers that prefer frameworks like CodeIgniter, Laravel, Kohana, and FuelPHP are very accustomed to using static methods in their application development. In some cases, it is an encouraged practice among these communities, who argue that it makes the code more readable and contributes to Rapid Application Development (RAD).

So, is there any kind of compromise?

Yep! Laravel 4 has a concept called "facades" (Note: This is not the same as the Facade design pattern). These act as a static interface, or proxy, to an actual object instance stored in a service container. The static proxy is linked to the container using a few tricks, including defining class aliases via PHP's class_alias() function, and the use of the magic __callStatic() method. We can thank Taylor Otwell for developing this technique.

OK, then what is the point of XStatic?

XStatic uses the same technique as Laravel's "facades" system, but provides two additional, but important, features:

  1. It works with any framework's service container - XStatic relies on the ContainerInterface of the container-interop project. You can use the Acclimate library to adapt any third-party containers to the normalized container interface that XStatic depends on.
  2. It works within any namespace - XStatic injects an autoloader onto the stack, so no matter what namespace or scope you try to reference your aliased static proxy from, it will pass through the XStatic autoloader. You can configure XStatic to create the aliases in the global namespace, the current namespace, or a specific namespace.

Oh, and why is it called XStatic?

Two reasons:

  1. It removes the static-ness of making static method invocations, since the method calls are proxied to actual object instances. Potential tagline: "Static interfaces without the static pitfalls".
  2. It is pronounced like the word "ecstatic", because it is meant to provide developers (some of them at least) with a sense of joy.

Usage

To show you how to use XStatic, I will show you a simple Silex application.

Your application bootstrap:

acclimate($app)); $proxyManager->addProxy('View', 'MyApp\Proxy\Twig'); $proxyManager->addProxy('DB', 'MyApp\Proxy\Pdo'); $proxyManager->enable(ProxyManager::ROOT_NAMESPACE_ANY); // Run the app $app->run();">


// Include the Composer autoloader, of course
require 'vendor/autoload.php';

use Acclimate\Container\ContainerAcclimator;
use XStatic\ProxyManager;
use Silex\Application;
use Silex\Provider\TwigServiceProvider;

// Setup your Silex app/container
$app = new Application;
$app->register(new TwigServiceProvider, array(
    'twig.path' => __DIR__ . '/templates',
));
$app['db'] = function () {
    return new PDO('mysql:dbname=testdb;host=127.0.0.1', 'dbuser', 'dbpass');
};
$app->get('/', 'MyApp\Controller\Home::index'); // Routes "/" to a controller object

// Setup and enable XStatic
$acclimator = new ContainerAcclimator();
$proxyManager = new ProxyManager($acclimator->acclimate($app));
$proxyManager->addProxy('View', 'MyApp\Proxy\Twig');
$proxyManager->addProxy('DB', 'MyApp\Proxy\Pdo');
$proxyManager->enable(ProxyManager::ROOT_NAMESPACE_ANY);

// Run the app
$app->run();

Your Static Proxy classes:

namespace MyApp\Proxy
{
    use XStatic\StaticProxy;

    class Pdo extends StaticProxy
    {
        public static function getInstanceIdentifier()
        {
            return 'db';
        }
    }

    class Twig extends StaticProxy
    {
        public static function getInstanceIdentifier()
        {
            return 'twig';
        }
    }
}

Your controller class:

namespace MyApp\Controller;

class Home
{
    public function index()
    {
        // It just works!
        View::render('home.index', array(
            'articles' => DB::query('SELECT * FROM articles')
        );
    }
}

Pretty cool, huh? Some interesting things to note about this example is that we've actually hidden the fact that we are using PDO and Twig from the controller. We could easily swap something else in that uses the same interfaces, and the controller code would not need to be altered. All we would need to do is put different objects into the application container. In fact, that is exactly how testing the controller would work. The test could be bootstrapped with mock or stub objects put into the container.

Static interfaces without the static pitfalls.

XStatic Concepts

  • Static Proxy – Static class that proxies static method calls to instance methods on its Proxy Subject.
  • Proxy Subject (Instance) – An object instance, stored in a Container, that is linked to a Static Proxy.
  • Proxy Manager – Mediating object used to associate Static Proxies to an Alias Loader and Container.
  • Alias – A memorable class name used as an alias to a fully-qualified class name of a Static Proxy class.
  • Alias Loader – Maintainer of the associations between Aliases and Static Proxies. It is injected into the autoloader stack to handle Aliases as they are referenced.
  • Container – A IoC container (e.g., a Service Locator or DIC) that provides the Proxy Subject instances. It must implement the container-interop project's ContainerInterface.
  • Instance Identifier – An identifier used to fetch a Proxy Subject from a Container. Each Static Proxy must specify the Instance Identifier needed to get its Proxy Subject.
  • Root Namespace – The namespace that an Alias can be referenced in. This can be configured as the global namespace (default), a specific namespace, or any namespace (i.e., the Alias works from any namespace).

How it works

The following diagram shows what happens when a Static Proxy is referenced, assuming it was previously added to the Proxy Manager.

XStatic Diagram

Inspiration

This library is heavily inspired by the Facades system in the Laravel 4 Framework.

Disclaimer

I would not consider myself to be for or against the use of static proxy interfaces (or Laravel's "Facades"), but I do think it is a fascinating and unique idea, and that it is very cool that you can write code this way and still have it work and be testable. I am curious to see if developers, especially library and framework developers, find ways to use, but not require, these static proxy interfaces in order to make their projects appeal to a wider range of PHP developers.

You might also like...
FreeSWITCH Event Socket Layer library for PHP

FreeSWITCH Event Socket Layer library for PHP Quickstart FreeSWITCH's Event Socket Layer is a TCP control interface enabling the development of comple

PHP Coroutine HTTP client - Swoole Humanization Library

PHP Coroutine HTTP client - Swoole Humanization Library

Software for an e-book library, in Bulgarian only. Based on Symfony3 and Doctrine 2.

chitanka.info core Това е уеб софтуер, който задвижва „Моята библиотека“. Изграден е с помощта на Symfony3, Doctrine 2 и много други прекрасни свободн

PHPneeds library (classes) package.
PHPneeds library (classes) package.

PHPneeds is a lightweight non-MVC PHP library for quickly start a project. About PHPneeds library (classes) package. Please use with PHPneeds base pro

Library for Open Swoole extension

Open Swoole Library This library works with Open Swoole since release version v4.7.1. WIP Table of Contents How to Contribute Code Requirements Develo

PSR-7 HTTP message library

PSR-7 Message Implementation This repository contains a full PSR-7 message implementation, several stream decorators, and some helpful functionality l

This repository contains a library of optional middleware for your Slim Framework application

Slim Framework Middleware This repository contains a library of optional middleware for your Slim Framework application. How to Install Update your co

This Slim Framework middleware will compile LESS CSS files on-the-fly using the Assetic library

This Slim Framework middleware will compile LESS CSS files on-the-fly using the Assetic library. It supports minification and caching, also via Asseti

🚀 This is a utility library that contains tools you may use everywhere.
🚀 This is a utility library that contains tools you may use everywhere.

Utilities Someday I will write documentation for this library, but for now, you can use it and see how it works. Introduction Some documentation will

Comments
  • How to access the container itself?

    How to access the container itself?

    Hi @jeremeamia

    I have a Silex app, and use xstatic to provide static proxy. I am able to access registered service such as db, twig, etc using the static proxy

    class View extends StaticProxy
    {
        public static function getInstanceIdentifier()
        {
            return 'twig';
        }
    }
    

    My question is, how to proxy the container itself? using laravel facade, I can do something like this

    class App extends Facade
    {
        protected static function getFacadeAccessor()
        {
            return self::$app;
        }
    
        public static function make($key)
        {
            return self::$app[$key];
        }
    }
    

    and still able to call all Silex method like App::register(new ServiceProvider()). I can also able to call App::make('some_service') to access static method of the static proxy class.

    Regards, Ikhsan

    opened by ikhsan017 2
  • Documentation incorrect

    Documentation incorrect

    There is a little error in documentation regarding the implementation of StaticProxies:

    class Pdo extends StaticProxy
        {
            public function getInstanceIdentifier()
            {
                return 'db';
            }
        }
    

    Should be:

    class Pdo extends StaticProxy
        {
            public static function getInstanceIdentifier()
            {
                return 'db';
            }
        }
    
    opened by pherrymason 2
  • Refactoring to support container-interop

    Refactoring to support container-interop

    • Now supports container-interop
    • Extract alias handling logic from XStatic into AliasLoader
    • Removed Jeremeamia from the namespace
    • Changed up the API significantly
    • Made the alias root namespace configurable
    • PSR-4 compatible

    This PR is WIP while I wrap up testing. Feedback is welcome.

    opened by jeremeamia 1
Releases(1.0.1)
Owner
Jeremy Lindblom
Sr Software Engineer at GoDaddy. OSS contributor, conference speaker, & community organizer in the PHP community. <3 OSS, PHP, APIs, & AWS
Jeremy Lindblom
Slim PHP static proxy library

#SlimStatic Slim PHP static proxy library. Contents About Usage API Customizing License About SlimStatic provides a simple static interface to various

John Stevenson 17 May 12, 2022
FreeSWITCH's Event Socket Layer is a TCP control interface enabling the development of complex dynamic dialplans/workflows

Asynchronous Event Socket Layer library for PHP Quickstart FreeSWITCH's Event Socket Layer is a TCP control interface enabling the development of comp

rtckit 3 Oct 11, 2022
PSR Log - This repository holds all interfaces/classes/traits related to PSR-3.

PSR Log This repository holds all interfaces/classes/traits related to PSR-3. Note that this is not a logger of its own. It is merely an interface tha

PHP-FIG 10.1k Jan 3, 2023
Socks5 proxy server written in Swoole PHP

php-socks This is a Socks5 proxy server implementation built with PHP & Swoole. To start the proxy server, clone this repo, run composer install to in

Nazmul Alam 3 Jan 23, 2022
A static analysis engine

A static analysis engine... Usage: bin/tuli analyze file1 file2 path Installation Install it as a composer dependency!!! $ composer require ircmaxell

Anthony Ferrara 171 Jan 31, 2022
"Static" interface for various Slim features

SlimFacades SlimFacades is a collection of facades for Slim PHP microframework, providing simple "static" interface for various Slim features. For exa

its 74 May 12, 2022
🚀 Coroutine-based concurrency library for PHP

English | 中文 Swoole is an event-driven asynchronous & coroutine-based concurrency networking communication engine with high performance written in C++

Swoole Project 17.7k Jan 8, 2023
🐘🎓📝 PHP Library providing an easy way to spellcheck multiple sources of text by many spellcheckers

PHP-Spellchecker Check misspellings from any text source with the most popular PHP spellchecker. About PHP-Spellchecker is a spellchecker abstraction

Philippe SEGATORI 257 Jan 2, 2023
PHP spell check library

php-speller PHP spell check library. Currently supported backends: aspell; hunspell; ispell. Installation With Composer: $ composer require mekras/php

Михаил Красильников 66 Oct 17, 2022
Lite & fast micro PHP abuse library that is **easy to use**.

Utopia Abuse Utopia framework abuse library is simple and lite library for managing application usage limits. This library is aiming to be as simple a

utopia 23 Dec 17, 2022