PHP Component and Library API Design Overview
There's been lots of change in the PHP community over the past few years. PHP now has namespaces. More PHP developers are using an IDE. More PHP developers are pulling inspiration from the Java, C#/.NET, and Ruby communities. And even more PHP developers are embracing the object-oriented and, ironically, the functional nature (closures) of PHP. All these changes make for interesting code. What has also happened is that better and more readable code is being produced by this ever growing PHP community. It's been a long time since a€oPHP applicationa€¯ meant a series of transaction scripts as a mix of SQL, CSS, JS, with some PHP sprinkled in, and a couple of few classes for good measure. Of course, that still exists, but you no longer need to go to the ends of the earth to find non-spaghetti code that is understandable within a few minutes.
For the most part, all of these changes are good changes. The number of good/senior/expert level PHP developers is ever increasing and there are more and more a€oenterprise gradea€¯ frameworks and libraries that are being produced. That said, with all of these new changes, the one area which is still fairly inconsistent from project to project is the naming conventions that are employed inside PHP 5.3 project that utilize namespaces. This article will attempt to describe what an API is, how names and object-oriented features affect an API, and how various decisions affect the consumers of a particular API is.
What Is An API?
Before we jump into naming, it's important to have a common understanding of the actual problem area. When we talk about names, we are really talking about the API. An API is a particular set of rules and specifications that a developer can follow to access and make use of the services and resources provided by another particular software program, component or library. Put another way, it is an interface between various software pieces and facilitates their interaction, similar to the way the user interface facilitates interaction between humans and computers.
For PHP 4 / procedural based libraries, the API is defined by the functions that are declared for usage in that library. It is further described by the global names and global state that the library utilizes to do its job. Typically, API's based on purely function based libraries are far simpler to understand.
Object-oriented API's are a bit more complex. When you build an object-oriented library or component, you are typically designing two API's at the same time, whether or not you know it. This is the nature of object-oriented languages when you employ the use of abstract classes and interfaces in your design.
The first API, the more common of the two, I call the Consumption API. This is the API that answers the question: a€ohow do people consume this thing.a€¯ The answer to this question is generally situated around the great majority of use cases that were identified by the author of the software component/library. In PHP, consumption might look like this:$foo = new SomeCompany\FooComponent\FooComponent($options); $foo-setAdapter(new SomeCompany\FooComponent\Adapter\SomeAdapter($adapterOptions)); $interestingResult = $foo-doSomethingInteresting();
As you can see, no declarative code was required to fulfill the most common use case that was identified as a need for this component's existence. The above API is defined by the totality of all the public (concrete) classes, their public properties and public methods. By examining these elements, a good API design should allow a developer to deduce how the component works without examining any documentation. When that is possible, the API has become the documentation as well as the a€ostorya€¯ behind how the component/library is to be used.
Not all use cases are accounted for in generic components and generic libraries. As developers, we attempt to create generic libraries and components that will solve the majority of problems of the majority of the community. We cannot envision all use cases or even edge cases behind a particular component. That said though doesn't means that the outlying use cases are unimportant or should be unaccounted for. These use cases are handled by the secondary API: the a€oExtension APIa€¯.
The Extension API answers the question: a€osince this component does 90% of what I want, how can I extend it to fulfill the last few of my needs.a€¯ Clearly, it makes sense to leverage tools that do most of what you need especially if they can be extended in ways that are outside of the out-of-the-box feature-set. Object-oriented/class based code is particularly well
Truncated by Planet PHP, read more at the original (another 8587 bytes)