Frequently Asked Questions

    Strictly speaking, statics are quite easy to test. li3 borrows several concepts from functional programming in order to ensure highly testable code throughout the entire framework, as well as applications built on top of it. In order to understand some of these concepts, first we have to define a few terms:

    State: An essential part of writing software, Wikipedia defines state as “a snapshot of the measure of various conditions in the system”. When developing PHP applications, this varies by context / scope: when the web server first loads up index.php, the state is defined by the data used to request the script, including GET or POST data, and any system information exposed in $_SERVER or $_ENV, as well as any other super-global variable. State can also include non-obvious things like the current date and time. Within a method, the state consists of any parameters passed in, anything within the object to which the method is bound (i.e. $this), and any other data defined or made available in the global scope.

    Side-effect: A concept closely related to state, side effects are changes that a method or other routine makes to things outside its own scope. Side effects include things like changing the values of global variables, object properties (i.e. $this), modifying data in a database or filesystem, changing the value of a parameter passed by reference, or echoing output.

    Mutability: Mutability is the quality of something which is changeable. The basic incarnation of mutability in PHP is a variable or object property. By contrast, something which is immutable is not changeable, i.e. a global or class-level constant. Therefore, mutable state is an element of application state (see above) that can be changed. These changes are what produce side-effects. This may seem obvious, but becomes more important later on.

    Getting back to our discussion, the problems with testing statics that people typically refer to actually have to do with mutable global state, i.e. a static method that depends on some external (usually global) piece of information which is subject to change by outside forces. The epitome of this anti-pattern is the Singleton. The idea behind singletons is that you have one (and only one) globally-available instance of an object at any one time.

    The essential problem with this is that there’s often no way to determine at any given time what the value of a singleton’s attributes could be, because any part of your application has access to modify them. This exemplifies the root cause of almost all software logic bugs. The only solution is to design the singleton such that, once created, its attributes cannot be changed (i.e., make it immutable). Alternatively, re-design the affected architecture so that a singleton is not required.

    Fortunately, all static classes in li3 are either composed of referentially transparent methods, or methods whose usage patterns are oriented around immutability. Some examples of referentially transparent methods are lithium\util\String::insert(), which inserts values into a template string, or lithium\util\Inflector::camelize(), which produces a version of a word or phrase. These functions have no external side-effects, and produce predictable output based on their parameters.

    Examples of immutable static classes would be any class extends , i.e. , Connections, etc. These classes model and provide access to system-level resources such as database connections, user sessions, and caching configurations. These classes are configured with information on how to access and operate on their respective resources using the config() method of each class. This happens once and only once, during the application’s bootstrap process. Subsequent access to those classes (i.e. through the adapter() method) always returns the same adapter instance with the same attributes. This avoids the problem of having our application’s state change out from under us.

    In this example, every call to B::bar() results in a call to A::foo(). It is impossible to test B in isolation, because it is impossible not to also call A. In PHP 5.2 and below, there was no solution to this. However, PHP 5.3 allows “dynamic” static method calls, which enable the following:

    This allows A to be swapped out for another class, and makes B much easier to test, since can be the name of a mock class that can act as a control during testing. This also has the pleasant side-effect of making B‘s design more flexible.

    li3 addresses this issue of dependencies in a uniform way, using the protected $_classes attribute. Consider the following snippet from the lithium\action\Dispatcher class:

    The Dispatcher‘s dependencies may then be dynamically configured to use a different routing class with the config() method. Internally, calling the Router looks like this:

    Some libraries are used by a single app or on an app-by-app basis. These apps store libraries in the /app/libraries directory. Other libraries are shared by one or more apps. The /libraries directory is provided to make administration of these libraries easier. There is also a (typically negligible) disk space savings as any given library isn’t duplicated in the /app/libraries directories for multiple applications.