Структура PHP-приложения: как эффективно использовать возможности языка
Использование PHP в структуре приложения
Как организовать PHP-приложение с использованием современных стандартов?
Наиболее эффективным решением является использование автозагрузки классов через Composer по стандарту PSR-4. Это позволяет автоматически подключать классы без ручных require. Пример структуры:
myapp/
src/
Controllers/
HomeController.php
Models/
User.php
public/
index.php
composer.jsonPhp app uses (использование приложения php)
В composer.json указываем автозагрузку:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}После запуска composer dump-autoload классы из пространства имен App будут найдены. В index.php достаточно написать:
require __DIR__ . '/../vendor/autoload.php';
use App\Controllers\HomeController;
$controller = new HomeController();
$controller->index();Этот подход обеспечивает чистую архитектуру, легкость поддержки и возможность использовать сторонние библиотеки через Composer.
Решение: проверять, что регистр директорий совпадает с namespace, перезапускать автозагрузку.
Как соединить несколько файлов без использования классов?
Можно использовать require или include для подключения файлов. Структура:
myapp/
includes/
header.php
footer.php
functions.php
index.phpВ index.php:
<?
require 'includes/functions.php';
require 'includes/header.php';
echo 'Главная страница
';
require 'includes/footer.php';Этот подход прост, но при росте приложения становится трудно поддерживать, возможны конфликты переменных.
Как организовать повторно используемые функции?
Создать файл с функциями, подключать его с require_once, чтобы избежать повторного подключения. Пример:
<? // helpers.php
function sanitize($data) { ... }
function redirect($url) { ... }В index.php: require_once 'helpers.php';
Как быстро создать REST API на PHP?
Установка через Composer: composer require slim/slim. Пример маршрута:
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require 'vendor/autoload.php';
$app = AppFactory::create();
$app->get('/hello/{name}', function (Request $request, Response $response, $args) {
$name = $args['name'];
$response->getBody()->write("Hello $name");
return $response;
});
$app->run();Запуск: php -S localhost:8080 -t public
Как отделить HTML от PHP кода?
Установка: composer require twig/twig. Создание шаблона:
// index.php
require 'vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader);
echo $twig->render('home.html.twig', ['name' => 'Мир']);Шаблон home.html.twig: <h1>Привет, {{ name }}!</h1>
Расширенные примеры организации приложения
Пример 1: Простое MVC приложение с собственным роутером.
Структура:
app/
core/
Router.php
Controller.php
controllers/
HomeController.php
models/
User.php
views/
home.php
public/
index.php
.htaccess
composer.jsonindex.php:
require __DIR__ . '/../vendor/autoload.php';
$router = new App\Core\Router();
$router->add('GET', '/', 'HomeController@index');
$router->dispatch();Router.php:
namespace App\Core;
class Router {
private $routes = [];
public function add($method, $path, $handler) {
$this->routes[] = compact('method', 'path', 'handler');
}
public function dispatch() {
$requestMethod = $_SERVER['REQUEST_METHOD'];
$requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
foreach ($this->routes as $route) {
if ($route['method'] === $requestMethod && $route['path'] === $requestUri) {
list($class, $method) = explode('@', $route['handler']);
$class = "App\\Controllers\\$class";
$controller = new $class();
$controller->$method();
return;
}
}
http_response_code(404);
echo '404 Not Found';
}
}HomeController:
namespace App\Controllers;
class HomeController {
public function index() {
$userModel = new \App\Models\User();
$users = $userModel->getAll();
require __DIR__ . '/../views/home.php';
}
}User model:
namespace App\Models;
use PDO;
class User {
private $db;
public function __construct() {
$this->db = new PDO('mysql:host=localhost;dbname=test', 'root', '');
}
public function getAll() {
$stmt = $this->db->query('SELECT * FROM users');
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}View home.php:
Список пользователей
<? foreach ($users as $user): ?>
- <?= htmlspecialchars($user['name']) ?>
<? endforeach; ?>
Результат при обращении к /: выведет список пользователей из БД. Если БД не настроена, будет ошибка подключения.
Пример 2: REST API с JSON ответом на чистом PHP (без фреймворка).
<?
// api/index.php
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$parts = explode('/', trim($uri, '/'));
$resource = $parts[0] ?? '';
$id = $parts[1] ?? null;
$data = ['message' => 'Hello API'];
if ($method === 'GET' && $resource === 'users') {
$data = [['id'=>1, 'name'=>'Alice'], ['id'=>2, 'name'=>'Bob']];
} elseif ($method === 'POST' && $resource === 'users') {
$input = json_decode(file_get_contents('php://input'), true);
$data = ['created' => $input];
}
echo json_encode($data, JSON_UNESCAPED_UNICODE);Запуск: php -S localhost:8080 -t api/
Результат запроса GET /users:
[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]Результат POST /users с телом {"name":"Charlie"}:
{"created":{"name":"Charlie"}}Пример 3: Использование шаблонизатора Twig с наследованием.
Создаем base.html.twig:
<!DOCTYPE html>
<html><head><title>{% block title %}{% endblock %}</title></head>
<body>{% block content %}{% endblock %}</body></html>page.html.twig:
{% extends "base.html.twig" %}
{% block title %}Главная{% endblock %}
{% block content %}<h1>Привет, {{ name }}</h1>{% endblock %}PHP код:
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader);
echo $twig->render('page.html.twig', ['name' => 'Мир']);Результат: HTML с заголовком "Главная" и телом "Привет, Мир".