This guide will show you some optional and smart ways how to structure files and directories in your PHP project.
PHP is very liberal and customizable when it comes to structuring project directories. If you’re planning to create a custom vanilla PHP application, you will need to invent the structure for your project. You will want a logical and understandable directory structure.
Open source PHP applications and frameworks have their own ways of structuring directories and files. If you’re using a framework or a CMS, you already have a directory structure defined. See links at the bottom for some common open source examples.
Complexity and nature of the project affect the required directories. For example, a web application will have additional publicly accessible directory compared to a command line application.
Structure your project the way you find it most logical and useful.
Let’s take a look the following example.
project-root/
.git/ # Git configuration and source directory
assets/ # Uncompiled/raw CSS, LESS, Sass, JavaScript, images
bin/ # Command line scripts
config/ # Application configuration
node_modules/ # Node.js modules for managing front end
public/ # Publicly accessible files at http://example.com/
index.php # Main entry point - front controller
...
src/ # PHP source code files
Controller/ # Controllers
...
templates/ # Template files
tests/ # Unit and functional tests
translations/ # Translation files
en_US.yaml
var/ # Temporary application files
cache/ # Cache files
log/ # Application specific log files
vendor/ # 3rd party packages and components with Composer
.gitignore # Ignored files and dirs in Git (node_modules, var, vendor...)
composer.json # Composer dependencies file
phpunit.xml.dist # PHPUnit configuration file
Above example has a longer list of directories in the root directory and less depth to browse for a particular file and locate them faster. You can merge certain types of files together or refactor that differently to suit your project needs. Find some balance for your use case between the too long list of items and too many subfolders to browse. When possible, apply separation of concerns.
Web applications need a publicly accessible directory. Above example uses name
public
. You can easily use pub
, web
, public_html
or your preferred name.
This directory will be accessible by the outside world when using a web server.
For security reasons, you should put only a minimal set of files required for
your application to work. This includes a single front controller, for example,
index.php
and static front end files (CSS, JavaScript, images…).
In case you have multiple configuration files, a good practice is to put
configuration files in their separate directory. Few examples:
config
or etc
or app/config
… Avoid putting configuration files in
a publicly accessible directory.
Composer helps you simplify and improve many aspects of your PHP application. For example, autoloading PHP classes, running scripts, automating the installation, managing 3rd party dependencies, and more.
The default special composer.json
file is located in the top root directory of
the project. In this file, all Composer configuration and dependencies are
defined.
The Composer creates a vendor
directory in the project root directory which
contains 3rd party dependencies (libraries, components, plugins…).
When it comes to PHP classes many projects, add them to a directory named src
or app
.
Above example includes all PHP files in the src
directory. These mainly include
the classes. The composer also includes a very neat feature - PSR-4 autoloading.
Adding the autoload
and autoload-dev
parts in the composer.json
will
autoload all classes for you:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
}
}
In modern PHP applications, structuring PHP files in the src
directory is part
of object oriented programming and design patterns. Each namespace is presented
with a subdirectory in the src
directory.
For example:
project-root/
...
src/
Controller/ # Classes for managing request and response by displaying
# templates with logic from services and or data from DB
Model/ # Classes for holding values from the database
Utils/ # Application services - business logic
...
...
Follow the OOP design patterns principles when adding classes into namespaces.
Your application should ideally also include tests. The above example uses the
tests
directory.
Depending on the complexity of the project a good practice is to split front end files (CSS, Sass, LESS, JavaScript, images…) and PHP backend files (PHP source code, templates, application configuration, unit tests… ) into two separate repositories.
In the above example the node_modules
directory is a standard directory (similar
to Composer’s vendor
) managed by Node.js tooling system - npm or yarn.
Instead of separating project into two repositories, the directory assets
is
used for storing uncompiled raw one or more of JavaScript, CSS, SaSS, LESS, images
and similar asset files which are compiled and processed to a public
directory.
In case you will not need more advanced and complex front end handling, you can
put these web assets directly into a public
directory.
By default, Composer creates a vendor
directory. Changing its name is not
a common approach because it’s a standard name used in the PHP ecosystem.
However, renaming can be done by setting a special environment variable
COMPOSER_VENDOR_DIR
:
COMPOSER_VENDOR_DIR=lib composer require phpunit/phpunit
or by manually adding a vendor-dir
configuration into composer.json
:
{
...
"config": {
"vendor-dir": "lib"
}
...
}
In case you will be deploying your PHP application to shared hostings with existing and predefined directory locations where you can upload private and public files, you will need to adjust the project directory structure accordingly.
Always avoid putting anything except the application’s public files into a
document root directory, such as public_html
, htdocs
or similar.
Some control panels might allow you to define the document root different than the default one:
public_html/ # Control panel's default document root directory
your-project/ # Your project with your preferred directory structure
...
config/
...
public/ # Set this directory as a new document root
src/
...