In this post we will actually start implementing out own framework. I assume you have installed php locally. We will now create our front controller and add routing setup.
The front controller will be the main entrypoint to our application. It is the first PHP file that is called and is tasked with bootstrapping the application and then running it.
Choose a project directory and open it in your favourite IDE. The project should be completely empty at this point. Let's create our first file and test it.
<?phpecho "Hello world"
Test your file by starting the php built-in server:
php -S localhost:8000 public\index.php
Composer is the pretty much universal package manager for php. Let's make our project a composer project. Install
composer using the instructions on their website. Then, create a composer.json file in your project root:
{"name": "your-name/your-framework","autoload": {"psr-4": {"Framework\\": "src/"}},"require": {}}
Next, run composer install to generate the autoloader. We will load that in our public/index.php file:
<?php // public/index.phprequire(__DIR__ . "../vendor/autoload.php");echo "Hello World!";
With this setup in place we can now install and use composer packages where we want. We can also use the autoloader
to load our files, as long as these files reside in the src/ dir and in the Framework namespace. Check the composer.json
for the exact path/namespace mapping.
Now, we cannot use the PSR-4 importer provided by composer in index.php because
composer is not yet loaded. That is why we will now create an Application class, load that from index.php and run
our application from there.
The new entry point looks like:
<?php // public/index.phprequire(__DIR__ . "/../vendor/autoload.php");require(__DIR__ . "/../src/Application.php");$application = new \Framework\Application();$response = $application->run();echo $response;
Then, let's implement the Framework\Application class in our second PHP file:
<?php // src/Application.phpnamespace Framework;class Application {public function run(): string {return "Hello World!";}}
What we do now is setup the application in our entry point index.php and let Application.php serve as our front
controller.
At this point you will probably want to test your application again. Start the server again as you did before and open your browser. You should still see the 'Hello World' thing.
One more thing: I have been working on the framework as discussed here in parallel. At this point I created a git repository so you can check out the state of the files you should have. If something is not working for you, you might be able to find any errors by comparing with the repository. I will share links to the repository at certain commits so you can easily check it out. Github repository at this point
The router's job is to execute the right code based on which URL is requested by the user. We have the REQUEST_URI
server variable available which holds the path and query string of the url.
Let's revisit the request flow diagram from the previous episode:
As you can see, the front controller (our Application class) will call the router and get a callable back (the controller). That callable will get called and its response given back to the Front Controller. The Front controller can then output the response for the user.
So, let's modify Application.php and create an implementation for the run function that gets a callable from the router, calls the callabe and return the result:
<?php // src/Application.phpnamespace Framework;class Application {public function run(): string {$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);$router = new Router();$callable = $router->getController($path);return $callable();}}
Now, we need to implement the Router class. As you can see the class should have a getController function that gets the path and returns a callable. Here is what the router looks like:
<?php // src/Router.phpnamespace Framework;class Router{public function getController(string $path): callable{$home = fn() => "Hello World!";$test = fn() => "Test route";return match ($path) {'/' => $home,'/test' => $test,};}}
For now, we have defined two test routes in the router itself. We will be replacing them with proper routes in the next episode.
If you now restart your server:
php -S localhost:8000 public\index.php
and open http://localhost:8000, you should see the "Hello World!" message again. If you now navigate to http://localhost:8000/test, you should see the second message 'Test route'!
Check the full state of the current project at GitHub
Now that we have a basic router working, let's start with the MVC part of our framework! Next up - creating our controllers!