Table of Contents
Let's Talk - Building a Modular PHP Framework part 2
Author(s): Louis Ouellet
Time for part 2! In our previous part, we set up the groundwork of our modular PHP framework. This time, we will focus on expanding its capabilities to support the following objectives:
- Add support for extensions
- Begin implementing a Command-Line module
- Add support for models to be used to create shared methods that require a database
- Add support for helpers to be used to create shared methods that do not require a database
These enhancements will provide the flexibility we need to build modular, maintainable, and extensible applications. Let's walk through each update step by step.
Updating the Bootstrap
We will begin by updating our Bootstrap
class to include helpers and models. We have also changed the default class for CLI
to LaswitchTech\Core\CLI
so that we can start working on it before exporting it into its own module.
Updating the Request Class
Next, let's update the Request
class so it can handle command-line arguments. In the constructor, we store the global $argv
in an Arguments
property (with a default empty array).
We then add a getArguments()
method for retrieving the arguments, and move any existing user-input retrieval methods (previously in coreCLI
) into this class.
Updating the Output Class
We also need to update the Output
class to handle both browser-based output and command-line output. Below is an example of how to handle CLI detection (STDIN
) and color-coded messages.
Implementing Helpers
Helpers provide small, shareable methods. To achieve this, we first create a base Helper
class that can be extended if we need shared properties or methods in the future.
Next, we implement the main Helpers
class to dynamically load individual helper files from both your application and any plugins.
Implementing Models
Models behave much like Helpers, but differ in that they usually require a database connection. We store a reference to the global $DATABASE
object in the base Model
class.
Just like Helpers, the Models
class dynamically loads all models from your /Model
folder and plugin directories:
Implementing the Command-Line Module
To implement a command-line interface (CLI), we'll create a template Command
class for developers to extend. Then we'll add a CLI
class that identifies and executes commands and actions.
Base Command Class
CLI Class
Testing the Code: Creating a "debug" Plugin
Let's create a simple plugin named debug
in /lib/plugins/debug/Command.php
. This demonstrates how to define custom commands to be handled by our new CLI infrastructure:
Running the CLI
Below is a sample script debug.php
in a tmp/
folder to test the CLI. Make it executable (chmod +x tmp/debug.php
) and run it like so:
./tmp/debug.php debug execute
Example Output
When you run:
./tmp/debug.php debug execute
You should see something like:
Variable Name: BOOTSTRAP = LaswitchTech\Core\Bootstrap Variable Name: REQUEST = LaswitchTech\Core\Request Variable Name: CLI = LaswitchTech\Core\CLI Variable Name: CONFIG = LaswitchTech\Core\Config Variable Name: LOG = LaswitchTech\Core\Log Variable Name: OUTPUT = LaswitchTech\Core\Output Variable Name: NET = LaswitchTech\Core\Strap Variable Name: HELPER = LaswitchTech\Core\Helpers Variable Name: DATABASE = LaswitchTech\Core\Strap Variable Name: MODEL = LaswitchTech\Core\Models Variable Name: LOCALE = LaswitchTech\Core\Strap Variable Name: SLS = LaswitchTech\Core\Strap Variable Name: SMS = LaswitchTech\Core\Strap Variable Name: SMTP = LaswitchTech\Core\Strap Variable Name: IMAP = LaswitchTech\Core\Strap Variable Name: INSTALLER = LaswitchTech\Core\Strap Host: localhost Parameter: CLI: Debugging... End of Script
Conclusion
GitHub Repository
In this second part of our series, we expanded our modular PHP framework to support command-line operations, helper classes, and models. By creating a generic CLI
class and a template Command
class, we can easily extend the framework with new commands and actions. The addition of Helpers
and Models
provides a cleaner, more organized way to share code across your application—making it easier to maintain and extend functionality without duplicating code.
Our framework is starting to take shape with clear separation of concerns and the flexibility to add or remove features as needed. In upcoming parts, we will continue to refine our framework, possibly by integrating more robust logging, configuration management, and additional modules that can further streamline development.
Tags
Discussion