Introducing Laminas for PHP Applications
In April 2019, the Linux Foundation announced that it was launching a new project: Laminas. This was actually the new name for a project that had existed since 2006, Zend Framework. From that moment on, the PHP framework, which already had 400 million installs, would have a vendor-neutral home. But Zend Technologies has not abandoned the product that bears its name for several years. Zend continues to provide corporate support, which includes mission-critical support, enterprise adapter extensions, long-term support, and on-demand guidance from PHP experts.
This chapter presents the evolution of the architecture of Zend Framework until its change to Laminas and discusses the lessons learned. In this chapter, you will gain an understanding of why the framework team took some decisions instead of others during its evolution. These subjects are the motivation for a developer to use a framework, and Laminas is presented as one option for PHP developers.
In this chapter, we’ll be covering the following topics:
- Why do we need web frameworks?
- From Zend Framework to Laminas
- The technical and social infrastructure of the Laminas community
Why do we need web frameworks?
Some people may ask, Why do I need a framework? Such people may also ask, Why do I need to use classes? After all, PHP is simple and it no needs classes. With a few lines of code, you can produce a page with processed data from a database. Rasmus Lerdorf, the PHP creator, always claimed in his talks that PHP is fast and it requires neither classes nor frameworks to work. In 2014, Mariano Iglesias gave a lecture at PHP Conference Brazil, in which he defended a future without frameworks. Well, both Rasmus and Mariano are right, depending on the software complexity we are talking about. We cannot compare a personal page with just a few statistics to an enterprise system. When we talk about object-oriented programming (OOP) and frameworks, we are mainly talking about complexity control.
Martin Fowler states that one of the meanings that most people agree on for the term architecture is a set of decisions that are hard to change. For a software project, these decisions are about the desirable characteristics of a piece of software. When you think about what is desirable for a piece of software, it is important to remember that the delivery of the first stable version of the software is only one milestone of its lifetime.
Continuous integration and continuous delivery
You must have heard of the terms continuous integration and continuous delivery. These approaches exist because change is continuous. Software can change for several reasons: new features might be needed because customers require them or because competitors already have them, bugs have to be fixed, computer platforms evolve, audiences grow, and legislation changes. So, customers, competitors, environments, and governments will force changes in software. We can have many doubts about the future, but one thing we can be sure of is that there will be changes.
“[...] a software engineering task where source code is both merged and tested on a mainline trunk. [...] Continuous integration is continuous because a developer can be continuously integrating software components while developing software.” You can read more about this in Hands-On Continuous Integration and Delivery, Jean-Marcel Belmont, Packt Publishing.
Jez Humble and David Farley, in their book Continuous Delivery, Addison-Wesley, define this term as the release of new features of software as frequently as possible to reduce the risk that delivery carries.
A piece of software is a growing organism. Frederick Brooks, in his book The Mythical Man-Month, Addison-Wesley, states that there are four levels of complexity for software:
- A program whose algorithm can be stored in only one human brain; in other words, only one person can understand it. It is a very specific program with a very limited task.
- A programming product: A program that can be run and maintained by anybody with minimal documentation and that is readable by human beings.
- A programming system: A set of programs where one program is combined with other programs to perform more complex tasks.
- A programming systems product: Software that is nine times more complex and expensive than a single program whose logic fits in the head of a single programmer.
This software requires a big team to maintain it. It cannot fit in a single person’s head. It is not easy to explain how it works or how it is organized. But, according to Brooks, it is the aim of most software development efforts.
The Mythical Man-Month is a classic text for software engineering. Although it was written before the rise of agile software development, its analysis of the complexity of producing software and the difficulty in parallelizing tasks remains current.
Complex software under continuous change requires some characteristics to be maintained for a long time. We are talking about software made to last and not to throw away after a week. Some software is ephemeral, so you do not have to worry so much about its structure. Automatic code generation tools are great for generating code that will soon be discarded. But software that will evolve requires a deep understanding of how software works. In fact, software made to last requires some key characteristics: minimal complexity, loose coupling, extensibility, and reusability. Each one of these desirable characteristics is related to one critical characteristic: ease of maintenance.
It seems contradictory to say that a complex system must have minimal complexity. In fact, when we say that a programming systems product is complex, we are talking about a system that has many parts and that is big. Minimal complexity refers to the internal organization of these parts and how they are connected. It is not expected that every member of the development team knows everything about the entire system at all times, but it is desirable that any member of the team can easily understand a part of the system so that they can change it when it is necessary.
Erich Gamma, when he was interviewed by Bill Venners, stated that current software environments are too complex to create applications without the reuse of existing code. Gamma presumes that OOP is the standard paradigm of development because it offers the extensibility that is essential to reuse. Gamma states that there are three levels of reuse in OOP: reuse of classes, reuse of patterns, and frameworks. He emphasizes that frameworks are the highest level of reuse because they identify the key abstractions for solving problems and offer implementations that contain the knowledge and experience of several developers.
You can read the complete interview with Erich Gamma at https://www.artima.com/articles/erich-gamma-on-flexibility-and-reuse.
The usefulness of a framework
When you use a framework to develop a piece of software, you are not only reusing classes like you do when you use libraries. Class libraries are like outsourcing in software development. You use class libraries because you want to focus on specific business issues, not on general issues that someone has already solved. But you call the classes of a library. A framework works under Hollywood’s Law: Don’t call us, we’ll call you. The framework classes call your classes. It takes care of the general behavior of the software and lets you define the custom behavior. When you use a framework, it is like your software is a franchisee. Your software shares the same infrastructure that other software has. When a franchisor solves a problem or improves some feature of the business, it solves for all franchisees. When a framework offers a solution for a problem, it solves a common problem for all applications that use it. As the Dungeon Master says, The fate of one is shared by all.
We use a framework to make software easy to maintain. So, a framework has to help us to create code with minimal complexity and to reuse existing code with loosely coupled components. Once a framework implements design and architectural patterns, it provides a solution to generic issues, and so, in its evolution, it focuses on the improvement of generic solutions. Erich Gamma states that a framework provides default functionalities at a high level. The focus on the default issues of a piece of software allows that framework to be in control of an application, like a manager or an advisor.
When we see a great software developer like Mariano Iglesias speaking against frameworks, he is actually speaking against something else: frameworkitis. As Bill Venners had it in his conversation with Erich Gamma, this term means “the disease of wanting to make frameworks out of everything.” Erich Gamma says that some software named as frameworks actually wants to do too much for developers. The problem is that when they try to do it, they do so in a way that not all developers want and – even worse – in a way that developers cannot change.
A real framework must say, “Do not worry, I control your application and will take care of the generic issues for you.” A framework with frameworkitis, in turn, says, “Do not worry, I generate code and do everything for you in the best way and you do not need to change my implementation – in fact, you cannot do so.” Well, this behavior goes in the opposite direction of a constantly changing scenario. Frameworkitis takes developers from love to hate. First, they love a tool that seems to do everything for them, and then they hate the tool to which they are tied and that they cannot change. Thank goodness that Laminas is not like that.
From Zend Framework to Laminas
In the opening of the movie X-Men (2000), Professor Xavier says that mutation is the key to our evolution. He adds that mutation is how we have evolved from single-celled organisms into the dominant species on the planet. Software is like a living organism. It needs to evolve in order to survive. Sometimes it needs to change a lot and it seems like a mutation. The need for change requires that software allows changes. A hard-to-change piece of software is a candidate for extinction.
Evolution for a piece of software might look like replacing one component with another. A replacement may be necessary for the maintenance or improvement of scalability, performance, or security. But if it is hard or almost impossible to replace a component of a piece of software, the improvements will have to be made in a difficult way, usually by rewriting the existing code.
Patterns help with the replacement of components as components share the same patterns. If each development team of a company creates software using different patterns for components, it will be difficult to share components, prohibiting reuse, which is a desirable characteristic for software made to last.
My introduction to Zend Framework
In 2005, I joined a large IT company with several software development units. This company developed government software and had thousands of projects in various programming languages. The problem was that each team used different standards for their projects, so component reuse was virtually non-existent. In addition, there was a history of decisions made in the past by tools with low initial coding that in the long run precipitated technology lock-in. Several teams used frameworks, but each one of them used different frameworks for the same language. So, the difficulty in sharing components remained.
In 2007, I was working for a division that was prospecting for new technologies and my team had to choose a framework to standardize PHP application development in the company. By coincidence, that year a seminar on PHP frameworks took place in the city of São Paulo. We went to this event and attended three talks, each about a framework: CakePHP, Symfony, and Zend. I already knew CakePHP from the first PHP Conference Brazil and several colleagues from my company already used Symfony. Zend Framework, however, was a complete novelty for me. This should not be a surprise because the first stable version of Zend Framework was released that year. But it had been in development since 2005.
The audience reaction to the CakePHP and Symfony lectures was similar. When the speakers executed the commands in the terminal that generated code, the audience said, Wow! But in Zend’s talk, when they saw that there was no code generator, they were disheartened. The speaker listened to the complaints and replied that although Zend did not have code generation tools, it was quite flexible, not imposing too much. Helpfully, one of the spectators noted that the framework architecture seemed to be concerned with maintaining the application and not just creating it.
On the way out of the event, I heard several people saying that they would use CakePHP or Symfony, emphasizing the code generation tools. These people probably did not have in-depth experience in software development, or rather in maintaining existing software. There are other tools that help with code generation, such as integrated development environments. Frameworks are reusable and are tools for reusing code, not new code creation tools.
One of the speakers was selling a book with an analysis of five frameworks, including the three presented at that event. I bought it, read it, and conducted tests for those frameworks, implementing the same application with each one of them. Among the five frameworks analyzed, the one that had the best characteristics of minimal complexity, loose coupling, extensibility, and reusability was Zend Framework. It was largely configurable and did not prevent the use of components from other frameworks. At the time, the PHP Framework Interoperability Group (PHP-FIG) did not yet exist, but we needed tools that offered interoperability.
PHP Framework Interoperability Group
In 2009, at PHP Conference Brazil, some PHP speakers gave a lecture called PHP Framewarks. It was a joking reference to a “war of frameworks.” Each one of the speakers defended their favorite framework and attacked the others. Maybe there was not exactly a war of frameworks, but the fact was that once you adopted a framework, it was difficult to use the components of others because each one followed its own patterns. This scenario began to change in the same year, 2009, when a group of PHP experts met in Chicago, USA, for establishing specifications of components for the PHP community. This group was first called PHP Standards Group. The first specification was about an autoloading standard – what helps the emergence of Composer. In 2011, the group changed its name to PHP Framework Interoperability Group (PHP-FIG). Since then, members of awesome PHP projects have met to discuss and write specifications called PHP Standard Recommendations (PSRs). Several frameworks and other PHP applications have adopted the specifications of PHP-FIG.
Zend Framework – the reference architecture for PHP applications
Zend Framework allowed us to create a reference architecture for PHP applications that helped applications to evolve. An application can use internal components, which are within its structure and serve only it, or make use of reusable components, which are shared by several applications. A component can perform a task that extrapolates the responsibilities of the reference architecture pattern implementations or even replace the implementation of a layer (but using the same interface).
To solve a given problem, the software architect must first look for an existing component that solves it. If it exists, but does not meet all the requirements, the possibility of extending it should be analyzed. Only as a last resort should a new component be created. In this case, the component is born as an internal component to meet a specific application. But the component architecture must be treated as generic so that it can be later published and improved so that it becomes a reusable component. Zend Framework had a structure concerned with these issues.
The first stable release of Zend Framework was released before PHP 5.3, so ZF1 did not use namespaces. There was no Composer yet, so ZF1 had its own autoload implementation. But the one aspect that Zend Framework had present in its structure was, as I mentioned, the possibility to change. In fact, the unstable versions already brought configurable code like this:
Instead of determining the directory for the controller classes, Zend Framework lets the developer choose. There was a proposed project structure, and today there is a Model-View-Controller (MVC) application skeleton available to start building an application, but the possibility to change the address of the project elements remains.
Another interesting feature of Zend Framework is recognizing that PHP applications already exist and you need to evolve what already exists. There will not always be demand for new projects, but what is in production needs to be maintained. Thus, Zend Framework allows from the beginning the use of components decoupled from the MVC implementation. Being able to refactor an application using Zend Framework components meant being able to outsource tasks that weren’t the focus of the application’s business without having to change everything. Change is necessary, but if it can be done slowly, gradually, and safely, it is better.
Zend Framework evolved gradually, keeping pace with the evolution of the PHP programming language and other software development technologies while incorporating design patterns and programming paradigms. In 2008, version 1.5 of Zend Framework incorporated the Two-Step View pattern with the
Zend_Layout component and delivered a component to create dynamic forms,
Zend_Form. In the same year, version 1.6 extended PHPUnit through the
Zend_Test component. In 2009, Zend Framework gained a code generation tool,
Zend_Tool, and a component for inversion of control,
Zend_Application. IDEs such as Eclipse and Netbeans soon offered integration with
Even in its first major version, Zend Framework started to offer, even optionally, the possibility of creating modules. Modules, in Zend Framework terminology, are self-contained units that can be reused. Module architecture is well suited to complex systems that must be divided into several subsystems. In a world of microservices, modules allow you to create an initially monolithic application that can gradually be converted into a distributed system.
You might ask, Why don’t we just create an application using microservices? The answer is another question: Is that really necessary? Today, we have elastic resources with cloud environments, but that is not a reason to allocate resources that we do not need yet. We do not need to change in advance but be prepared for change. The cake has an adequate amount of time to bake.
In version 2.0, Zend Framework evolved the module architecture and improved the consistency and performance of the components. The code was refactored to use namespaces and two new components were incorporated:
EventManager, a combination of several strategies for event-driven programming used by the MVC implementation, and
ServiceManager, a container for dependency injection. Decoupling between components has increased significantly since version 2.0.
Version 2.5 brought radical changes to Zend Framework. Each component was given its own version control repository and had an independent lifecycle. In addition, the autoloading of classes and the installation of components is now done by Composer. Until version 2.4, Zend Framework was a download everything but just use what you want framework. As of version 2.5, it became a download and use only what you want framework.
Version 3.0 of Zend Framework updated the minimum dependency on PHP to version 7, taking advantage of improvements implemented in the language. In addition, Zend Framework 3.0 brought a special microframework for creating middleware, Expressive. This microframework was implemented in strong compliance with PSRs from PHP-FIG, with complete independence from the components to be used.
And that was the end of Zend Framework. Yes, that was the end of it, because as we said at the beginning of the chapter, it is now called Laminas. Lamina means blade. The reason for this name is that the framework allows the creation of applications in layers, but thin layers, that is, with minimum necessary layer size. As Professor X said, evolution is slow. But sometimes evolution leaps forward. The change from Zend Framework to Laminas required a refactoring of all class names. In addition, the technical and social infrastructure of the community also changes. But this leap was good, because a framework with so many years of experience is more open now. And you are going to learn it here!
The differences between Zend Framework and Laminas
There are some differences between Zend Framework and Laminas as regards the community ecosystem. Zend Framework, as an open source project, accepted code contributions. Laminas, in turn, can also receive donations because it is under a non-profit organization. Zend Framework had forums and a Slack channel for the community to have discussions and make contributions. Laminas, in addition, has monthly open-to-the-public meetings and keeps a record of Technical Steering Committee votes (TSC is a group of members with technical knowledge that governs the project). In other words, Laminas is more open to community participation and transparent than Zend Framework. This is good! You can - if you wish – participate actively in the development of a product that helps you to create object-oriented web applications with several design patterns built in.
Steve McConnell states that the choice of programming language is a key construction decision for a software project. The PHP community, in turn, states that PHP is especially suited for web development. But the programming language is only one of the aspects you need to worry about when creating and maintaining web application projects. That’s why we are talking about Laminas.
The technical and social infrastructure of the Laminas community
We will talk about many features of Laminas, but we will not cover everything, of course. The main reference source for Laminas is the official documentation, available at https://docs.laminas.dev.
Figure 1.1 – Documentation home page for Laminas
The Components and MVC options on the documentation home page are directly related to the content of this book. Laminas, however, also includes the microframework Mezzio – formerly known as Expressive – and API Tools, an API generator built in with Laminas components.
The source code of all components is available for download and contribution at https://github.com/laminas. You will find more than 100 repositories with mature components. On this page, you can open issues for fixing bugs or requesting new features – remembering that for features, the level of response you get will depend on the interest of the community. If you have an idea for improving an existing component or even for creating a new component, be encouraged to send an implementation and not only a specification. Contributing to a free and open source project is an awesome way to learn more about software development and can help you to become known by your peers, who can then become your advisors. The guidelines for contributing to Laminas are available at https://github.com/laminas/.github/blob/main/CONTRIBUTING.md.
Roger Pressman defines software as a combination of computer programs and documentation about those programs. People are also part of a piece of software’s documentation, because they often hold tacit knowledge that has not yet been converted into explicit knowledge. When documentation is not enough, we may need help from people, and a recorded conversation can become documentation. You can chat with people involved or interested in Laminas in the official discussion forums, available at https://discourse.laminas.dev.
You can get support from the community by opening issues and posting your questions on the forums; you can even solve issues yourself by extending components. But if you want on-demand consultative support or long-term support, you can think about the enterprise support of Zend Technologies. For more information about this service, read https://www.zend.com/products/laminas-enterprise-support.
After this overview of Laminas, in the next chapter, we will prepare an environment for developing with this framework.
Software is like a living organism: it is born, it grows, and someday it dies. We do not want our software to die early, of course. For this, we need to provide our software with characteristics that allow it to survive for a long time. In this chapter, we spoke about frameworks that help us to create reusable and easy-to-maintain software.
We touched on the history of Laminas, a free and open source framework for building PHP web applications. We presented its evolution and its proposal as a framework for evolving applications.
In the next chapter, we will prepare our environment to develop PHP web applications with Laminas.