Create Your First Modern PHP Project
A new PHP project shouldn’t start with a single index.php file stuffed with HTML and SQL. Modern PHP development begins with good engineering habits: dependency management, autoloading, version control, and a clean directory structure. This tutorial will walk you through building your very first PHP project the professional way—using PHP 8.4, Composer, Git, and the principles that underpin every maintainable PHP application.
By the end, you’ll have a small, framework‑independent project that prints a friendly greeting. More importantly, you’ll understand the foundational practices that make PHP projects scalable, testable, and ready for real‑world growth.
Prerequisites​
Before you start, make sure you have completed the environment setup guide:
- PHP 8.4, Composer, Git, and VS Code are installed.
- Your terminal is ready and
php -v,composer --version, andgit --versionall return the expected output.
If you need help, refer to the installation guide.
Project Overview​
We’ll create a project called hello-phpdevpro that:
- Uses Composer to manage dependencies and autoloading.
- Organizes code into a
src/directory with a single class. - Places the public entry point in a
public/folder. - Initializes Git from the start.
- Follows PSR-4 for autoloading.
This tiny application is the seed of every professional PHP codebase you’ll ever work on.
Create the Project Directory​
Open your terminal and create a new folder for your project:
mkdir hello-phpdevpro
cd hello-phpdevpro
A dedicated directory keeps all project files organized and is the first step toward treating your work as a real software project, not just a collection of loose scripts.
Initialize Git​
Version control tracks changes and lets you experiment safely. Initialize a Git repository immediately:
git init
Now create a .gitignore file to tell Git which files and folders should not be committed. Add the following content:
# Composer
/vendor/
# Environment
.env
.env.local
.env.*.local
# IDE
.vscode/
.idea/
# OS files
.DS_Store
Thumbs.db
The vendor/ directory contains third‑party packages managed by Composer; they are never committed directly. Instead, composer.json and composer.lock define exactly which packages and versions are used, so any developer can recreate the environment with composer install.
Save the file and make your first commit later, after we generate some project files.
Initialize Composer​
Composer is the heart of PHP’s ecosystem. Run the interactive initializer:
composer init
Answer the prompts. You can press Enter to accept defaults for most fields, but fill in these important ones:
- Package name (
<vendor>/<name>) – use something likephpdevpro/hello-phpdevpro - Description –
A first modern PHP project - Author – your name and email
- Minimum Stability –
stable - Package Type –
project - License – choose one, e.g.,
MIT
After the prompts, Composer will generate a composer.json file. Then run:
composer install
This command creates a composer.lock file and a vendor/ directory containing the autoloader (and any packages we later add). Right now there are no dependencies, but the autoloader infrastructure is in place.
Understand composer.json​
Open composer.json. It should look similar to this:
{
"name": "phpdevpro/hello-phpdevpro",
"description": "A first modern PHP project",
"type": "project",
"require": {
"php": ">=8.4"
},
"require-dev": {},
"autoload": {},
"authors": [
{
"name": "Your Name",
}
],
"minimum-stability": "stable"
}
Key sections explained:
- require – production dependencies; we’ve specified the PHP version, but soon you’ll add libraries here.
- require-dev – development‑only tools like PHPUnit or PHPStan.
- autoload – tells Composer how to load your own classes. We’ll configure PSR‑4 here.
- scripts – (not shown) custom commands that Composer can run, such as
"start": "php -S localhost:8000 -t public".
This single file defines your entire project’s identity and dependencies. It’s your blueprint.
Configure PSR‑4 Autoloading​
In old PHP tutorials you’ll see require 'file.php' scattered everywhere. Modern PHP uses an autoloader that automatically loads classes when they are first needed. PSR‑4 is the standard that maps namespaces to directory paths.
Add the autoload section to composer.json:
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
This tells Composer: “Any class under the App namespace will be found inside the src/ directory.” So App\Greeter will be expected at src/Greeter.php.
Now regenerate the autoloader:
composer dump-autoload
Composer will update the vendor/composer/autoload_*.php files. From now on, you’ll never write require for your own classes again—just use use statements and the autoloader handles the rest.
Create a Modern Project Structure​
Let’s build the actual directories. A well‑organized project separates concerns:
mkdir src public tests
After these commands, your folder should look like:
hello-phpdevpro/
├── src/ # Your PHP classes (App namespace)
├── public/ # The only directory exposed to the web
├── tests/ # Automated tests (we'll use later)
├── vendor/ # Composer managed packages
├── composer.json # Project metadata and dependencies
├── composer.lock # Exact dependency versions
├── .gitignore # Files excluded from version control
└── README.md # Project documentation (create this now)
- src/ – all your application logic. This is the core of your project.
- public/ – contains the entry point (
index.php) and any publicly accessible assets (CSS, JS, images). When deploying, only this directory should be visible to the web server. - tests/ – where your unit and integration tests will live.
- vendor/ – never touch this directly; it’s managed by Composer.
This structure is framework‑agnostic, but it’s the same foundation used by Laravel, Symfony, and any well‑designed PHP package.
Write Your First PHP Class​
Now we’ll create a simple class that generates a greeting. Create the file src/Greeter.php:
<?php
declare(strict_types=1);
namespace App;
class Greeter
{
public function greet(): string
{
return "Hello, PHPDevPro!";
}
}
Let’s examine what makes this a modern PHP class:
declare(strict_types=1);enforces strict typing for this file. Type mismatches will throw errors instead of silently coercing values. Always use it.namespace App;places the class inside theAppnamespace, matching our PSR‑4 mapping.public function greet(): stringdeclares a public method that returns astring. The return type ensures the method’s contract is explicit.
This tiny class already demonstrates namespaces, strict typing, and return types—core features of modern PHP engineering.
Create the Entry Point​
Every PHP application has a single entry point. Create public/index.php:
<?php
declare(strict_types=1);
// Load Composer's autoloader
require_once __DIR__ . '/../vendor/autoload.php';
use App\Greeter;
// Instantiate and use the Greeter
$greeter = new Greeter();
echo $greeter->greet() . PHP_EOL;
Breaking it down:
require_once __DIR__ . '/../vendor/autoload.php';loads Composer’s autoloader. Once included, all your classes and any installed third‑party libraries become available automatically.use App\Greeter;imports the class so you can refer to it without the full namespace.$greeter = new Greeter();creates an instance.echo $greeter->greet() . PHP_EOL;prints the greeting followed by a newline.
That’s it—no manual require for Greeter.php. The autoloader finds it automatically based on the namespace and the PSR‑4 mapping.
Run the Project​
Run your project from the command line:
php public/index.php
Expected output:
Hello, PHPDevPro!
Congratulations! You’ve just built a modern PHP project. All the hard work—Composer, autoloading, directory structure—pays off every time you add a new class or install a library.
Understanding the Request Flow​
Let’s visualise how a request flows through your application.
The entry point boots the autoloader, which loads the required class on demand. The class performs its logic and returns a result, which is then sent back to the user. This separation of concerns is the bedrock of maintainable systems.
Why This Structure Matters​
You might wonder, “All this just to print a greeting?” Yes—because the same structure holds for applications with hundreds of classes.
- Maintainability – each class has a single, predictable location.
- Scalability – adding a new feature means adding a new file in
src/, not hunting through a giant file. - Testability – you can write unit tests that load only the class they need, without executing the whole app.
- IDE support – modern editors like VS Code provide intelligent autocompletion and navigation because they understand the namespace structure.
- Framework readiness – when you later adopt Laravel or Symfony, their directory structures will feel completely natural.
- Clean separation – business logic (
src/) is isolated from the web layer (public/), so you can replace the UI or run the same code from the command line.
Starting with these habits ensures you won’t have to unlearn bad practices later.
Common Beginner Mistakes​
Even with a simple project, a few traps await. Here’s what to watch out for:
- Putting everything in one file – resist the urge to dump all functions in
index.php. As the project grows, that file becomes unreadable. - Skipping Composer – even a tiny project benefits from autoloading. Composer is not just for big frameworks.
- Ignoring namespaces – classes outside any namespace risk naming collisions with other libraries.
- Editing
vendor/– never manually change files invendor/. Your changes will be wiped on the nextcomposer update. - Not using Git – accidents happen. Version control gives you a safety net and tracks your learning progress.
- Committing unnecessary files – avoid committing
vendor/,.env, and IDE‑specific folders.
If you fall into one of these, don’t panic. The important thing is to recognize why it’s a problem and fix it early.
Next Steps​
Your tiny project is a complete, modern PHP application. Now it’s time to fill in the details of the language itself.
- PHP Language Fundamentals – learn variables, types, control flow, and functions in depth.
- Object‑Oriented Programming – master classes, interfaces, traits, and enums.
- Composer in Depth – understand version constraints, autoloading optimizations, and scripts.
- Runtime – discover what happens behind the scenes when PHP executes your code.
Start with the Foundations—they are the key to turning this seed into a robust backend system.
Recommended Reading​
| Article | Link |
|---|---|
| PHP Language Fundamentals | /foundations/php-language-fundamentals/ |
| Object‑Oriented Programming in PHP | /foundations/object-oriented-programming/ |
| Composer Dependency Management | /foundations/composer/ |
| PHP Runtime Overview | /runtime/php-runtime-overview/ |
| PHP Architecture | /architecture/ |
Frequently Asked Questions​
Why use Composer for a simple project?​
Because it gives you autoloading, dependency management, and a standard project structure from the start. As soon as you need a library—say, for logging or a database—you’re ready.
What is PSR‑4 autoloading?​
It’s a standard that maps namespace prefixes to directories. For example, App\ maps to src/. When you use a class, Composer’s autoloader knows exactly where to find it without any manual require.
Should I use a framework immediately?​
No. Learning the fundamentals first makes you a far better framework user. This project’s structure is exactly what frameworks build upon—you’ll appreciate them more after seeing the raw version.
Why create a public directory?​
It separates the code the outside world can access from your internal application logic. Only public/index.php is reachable; all other files stay safely outside the web root, a crucial security practice.
Why shouldn’t I edit the vendor folder?​
Vendor files are managed by Composer. Any manual changes will be overwritten the next time you run composer update. If you need to modify a package, fork it and reference the fork.
Do I need Git for personal projects?​
Yes. Git lets you track changes, revert mistakes, and experiment in branches without fear. It’s an essential tool regardless of team size.
Can I build APIs with this structure?​
Absolutely. You’d replace the Greeter class with controllers and route handling, but the core project layout stays the same. In fact, most API frameworks encourage exactly this src/ and public/ separation.
How is this different from traditional PHP tutorials?​
Traditional tutorials often start with a single file mixing HTML and PHP, using require for includes. This project introduces Composer, PSR‑4, namespaces, and a clean folder structure from day one—the practices used in professional PHP development.
When should I learn Laravel?​
After you’re comfortable with the concepts in this tutorial and the Foundations section: OOP, Composer, dependency injection, and PSR standards. That knowledge will make Laravel feel like a natural extension, not magic.
What should I study next?​
Proceed to PHP Language Fundamentals to deepen your understanding of the syntax and types that power every PHP application.
Key Takeaways​
- A modern PHP project starts with Composer, Git, and a clean directory structure.
- PSR‑4 autoloading replaces manual
requireand scales elegantly. - Keep your source code in
src/, your entry point inpublic/, and your tests intests/. - Even a single‑class project benefits from namespaces, strict typing, and the Composer autoloader.
- Good habits built now will make learning frameworks and architectures much easier later.
Conclusion​
You’ve built your first modern PHP project—not a toy, but a miniature version of the professional PHP applications that power the web. You used Composer, PSR‑4, Git, and a carefully chosen directory layout. The code is simple, but the practices are exactly what you’ll rely on when you design APIs, integrate databases, or start your next SaaS idea.
Keep this project as a template. The next time you start something new, clone the structure and focus on your logic, not on the setup. From here, dive into the Foundations section and turn your understanding of PHP into an engineering superpower.
Welcome to modern PHP development. Your journey has just begun.