程序结构
概述
了解如何组织PHP程序对于编写可维护、可扩展的应用程序至关重要。本章涵盖文件组织、命名空间、自动加载以及帮助您有效构建PHP项目的架构模式。
文件组织
基本文件结构
my-php-project/
├── public/ # Web可访问文件
│ ├── index.php # 入口点
│ ├── css/
│ ├── js/
│ └── images/
├── src/ # 应用程序源代码
│ ├── Models/
│ ├── Controllers/
│ └── Views/
├── config/ # 配置文件
├── tests/ # 测试文件
├── vendor/ # Composer依赖
├── composer.json # 依赖管理
└── .htaccess # Apache配置单文件程序
php
<?php
// simple_calculator.php
// 配置
error_reporting(E_ALL);
ini_set('display_errors', 1);
// 函数
function add($a, $b) {
return $a + $b;
}
function subtract($a, $b) {
return $a - $b;
}
function multiply($a, $b) {
return $a * $b;
}
function divide($a, $b) {
if ($b == 0) {
throw new InvalidArgumentException("除数为零");
}
return $a / $b;
}
// 主程序逻辑
try {
$num1 = 10;
$num2 = 5;
echo "加法: " . add($num1, $num2) . "\n";
echo "减法: " . subtract($num1, $num2) . "\n";
echo "乘法: " . multiply($num1, $num2) . "\n";
echo "除法: " . divide($num1, $num2) . "\n";
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
?>多文件程序
config/database.php
php
<?php
return [
'host' => 'localhost',
'database' => 'myapp',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4'
];
?>src/Database.php
php
<?php
class Database {
private $connection;
public function __construct($config) {
$dsn = "mysql:host={$config['host']};dbname={$config['database']};charset={$config['charset']}";
$this->connection = new PDO($dsn, $config['username'], $config['password']);
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function getConnection() {
return $this->connection;
}
}
?>src/User.php
php
<?php
class User {
private $db;
public function __construct(Database $database) {
$this->db = $database->getConnection();
}
public function create($name, $email) {
$stmt = $this->db->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
return $stmt->execute([$name, $email]);
}
public function findById($id) {
$stmt = $this->db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
}
?>public/index.php
php
<?php
// 包含所需文件
require_once '../src/Database.php';
require_once '../src/User.php';
// 加载配置
$config = require '../config/database.php';
// 初始化应用程序
try {
$database = new Database($config);
$userModel = new User($database);
// 应用程序逻辑
$user = $userModel->findById(1);
if ($user) {
echo "欢迎," . htmlspecialchars($user['name']);
} else {
echo "用户未找到";
}
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>Include和Require
Include vs Require
php
<?php
// include - 如果找不到文件则继续执行(警告)
include 'optional_file.php';
// require - 如果找不到文件则停止执行(致命错误)
require 'essential_file.php';
// include_once - 只包含文件一次
include_once 'header.php';
// require_once - 只要求文件一次(推荐用于类)
require_once 'User.php';
?>Include的最佳实践
php
<?php
// 使用绝对路径避免问题
require_once __DIR__ . '/config/database.php';
// 定义常用路径的常量
define('ROOT_PATH', __DIR__);
define('SRC_PATH', ROOT_PATH . '/src');
define('CONFIG_PATH', ROOT_PATH . '/config');
require_once SRC_PATH . '/User.php';
require_once CONFIG_PATH . '/database.php';
?>命名空间
基本命名空间用法
php
<?php
// src/Models/User.php
namespace App\Models;
class User {
public function getName() {
return "Models命名空间中的用户";
}
}
?>php
<?php
// src/Controllers/User.php
namespace App\Controllers;
class User {
public function index() {
return "用户控制器";
}
}
?>php
<?php
// 使用命名空间类
require_once 'src/Models/User.php';
require_once 'src/Controllers/User.php';
// 完全限定名
$userModel = new \App\Models\User();
$userController = new \App\Controllers\User();
// 使用use语句
use App\Models\User as UserModel;
use App\Controllers\User as UserController;
$model = new UserModel();
$controller = new UserController();
?>命名空间别名
php
<?php
namespace App\Services;
// 使用别名导入类
use App\Models\User as UserModel;
use App\Repositories\User as UserRepository;
use DateTime;
class UserService {
private $userModel;
private $userRepository;
public function __construct() {
$this->userModel = new UserModel();
$this->userRepository = new UserRepository();
}
public function createUser($data) {
$data['created_at'] = new DateTime();
return $this->userRepository->save($data);
}
}
?>全局命名空间
php
<?php
namespace App\Models;
// 使用前导反斜杠访问全局类
$date = new \DateTime();
$pdo = new \PDO($dsn, $user, $pass);
// 或者导入它们
use DateTime;
use PDO;
$date = new DateTime();
$pdo = new PDO($dsn, $user, $pass);
?>自动加载
手动自动加载
php
<?php
// autoload.php
spl_autoload_register(function ($className) {
// 将命名空间转换为文件路径
$file = str_replace('\\', DIRECTORY_SEPARATOR, $className) . '.php';
$fullPath = __DIR__ . '/src/' . $file;
if (file_exists($fullPath)) {
require_once $fullPath;
}
});
// 用法
require_once 'autoload.php';
// 这些类将被自动加载
$user = new App\Models\User();
$controller = new App\Controllers\UserController();
?>PSR-4自动加载
php
<?php
// composer.json
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
?>php
<?php
// 运行后:composer dump-autoload
require_once 'vendor/autoload.php';
// 类会根据命名空间自动加载
$user = new App\Models\User(); // 加载 src/Models/User.php
$service = new App\Services\UserService(); // 加载 src/Services/UserService.php
?>面向对象结构
类组织
php
<?php
namespace App\Models;
use DateTime;
use InvalidArgumentException;
/**
* 用户模型类
*/
class User {
// 常量
const STATUS_ACTIVE = 1;
const STATUS_INACTIVE = 0;
// 属性
private $id;
private $name;
private $email;
private $status;
private $createdAt;
// 构造函数
public function __construct($name, $email) {
$this->setName($name);
$this->setEmail($email);
$this->status = self::STATUS_ACTIVE;
$this->createdAt = new DateTime();
}
// Getters
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
public function getEmail() {
return $this->email;
}
// Setters with validation
public function setName($name) {
if (empty($name)) {
throw new InvalidArgumentException("Name cannot be empty");
}
$this->name = trim($name);
}
public function setEmail($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("Invalid email format");
}
$this->email = $email;
}
// Business logic methods
public function activate() {
$this->status = self::STATUS_ACTIVE;
}
public function deactivate() {
$this->status = self::STATUS_INACTIVE;
}
public function isActive() {
return $this->status === self::STATUS_ACTIVE;
}
// Utility methods
public function toArray() {
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'status' => $this->status,
'created_at' => $this->createdAt->format('Y-m-d H:i:s')
];
}
}
?>Interface and Abstract Classes
php
<?php
namespace App\Contracts;
interface UserRepositoryInterface {
public function find($id);
public function save(User $user);
public function delete($id);
}
?>php
<?php
namespace App\Repositories;
use App\Contracts\UserRepositoryInterface;
use App\Models\User;
abstract class BaseRepository {
protected $connection;
public function __construct($connection) {
$this->connection = $connection;
}
abstract protected function getTableName();
}
class UserRepository extends BaseRepository implements UserRepositoryInterface {
protected function getTableName() {
return 'users';
}
public function find($id) {
$stmt = $this->connection->prepare("SELECT * FROM {$this->getTableName()} WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function save(User $user) {
// Implementation
}
public function delete($id) {
// Implementation
}
}
?>MVC Architecture Pattern
Model-View-Controller Structure
src/
├── Models/
│ ├── User.php
│ └── Product.php
├── Views/
│ ├── users/
│ │ ├── index.php
│ │ └── show.php
│ └── layouts/
│ └── main.php
├── Controllers/
│ ├── BaseController.php
│ └── UserController.php
└── Core/
├── Router.php
└── Application.phpBase Controller
php
<?php
namespace App\Controllers;
abstract class BaseController {
protected function render($view, $data = []) {
extract($data);
ob_start();
include __DIR__ . "/../Views/{$view}.php";
$content = ob_get_clean();
include __DIR__ . "/../Views/layouts/main.php";
}
protected function redirect($url) {
header("Location: {$url}");
exit;
}
protected function json($data) {
header('Content-Type: application/json');
echo json_encode($data);
exit;
}
}
?>User Controller
php
<?php
namespace App\Controllers;
use App\Models\User;
use App\Repositories\UserRepository;
class UserController extends BaseController {
private $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function index() {
$users = $this->userRepository->findAll();
$this->render('users/index', ['users' => $users]);
}
public function show($id) {
$user = $this->userRepository->find($id);
if (!$user) {
$this->redirect('/users');
}
$this->render('users/show', ['user' => $user]);
}
public function create() {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$user = new User($_POST['name'], $_POST['email']);
$this->userRepository->save($user);
$this->redirect('/users');
} catch (Exception $e) {
$this->render('users/create', ['error' => $e->getMessage()]);
}
} else {
$this->render('users/create');
}
}
}
?>Configuration Management
Environment-Based Configuration
php
<?php
// config/app.php
return [
'name' => $_ENV['APP_NAME'] ?? 'My Application',
'debug' => $_ENV['APP_DEBUG'] ?? false,
'url' => $_ENV['APP_URL'] ?? 'http://localhost',
'database' => [
'host' => $_ENV['DB_HOST'] ?? 'localhost',
'name' => $_ENV['DB_NAME'] ?? 'myapp',
'user' => $_ENV['DB_USER'] ?? 'root',
'pass' => $_ENV['DB_PASS'] ?? '',
],
'mail' => [
'driver' => $_ENV['MAIL_DRIVER'] ?? 'smtp',
'host' => $_ENV['MAIL_HOST'] ?? 'localhost',
'port' => $_ENV['MAIL_PORT'] ?? 587,
]
];
?>Configuration Class
php
<?php
namespace App\Core;
class Config {
private static $config = [];
public static function load($file) {
$path = __DIR__ . "/../../config/{$file}.php";
if (file_exists($path)) {
self::$config[$file] = require $path;
}
}
public static function get($key, $default = null) {
$keys = explode('.', $key);
$value = self::$config;
foreach ($keys as $k) {
if (!isset($value[$k])) {
return $default;
}
$value = $value[$k];
}
return $value;
}
}
// Usage
Config::load('app');
Config::load('database');
$appName = Config::get('app.name');
$dbHost = Config::get('app.database.host');
?>Error Handling Structure
Custom Exception Classes
php
<?php
namespace App\Exceptions;
class ValidationException extends \Exception {
private $errors;
public function __construct($errors, $message = "Validation failed") {
parent::__construct($message);
$this->errors = $errors;
}
public function getErrors() {
return $this->errors;
}
}
class DatabaseException extends \Exception {
// Custom database exception handling
}
?>Global Error Handler
php
<?php
namespace App\Core;
use App\Exceptions\ValidationException;
class ErrorHandler {
public static function register() {
set_error_handler([self::class, 'handleError']);
set_exception_handler([self::class, 'handleException']);
register_shutdown_function([self::class, 'handleShutdown']);
}
public static function handleError($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
return false;
}
throw new \ErrorException($message, 0, $severity, $file, $line);
}
public static function handleException($exception) {
if ($exception instanceof ValidationException) {
self::renderValidationError($exception);
} else {
self::renderGenericError($exception);
}
}
public static function handleShutdown() {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR])) {
self::handleException(new \ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']));
}
}
private static function renderValidationError(ValidationException $e) {
// Render validation error page
}
private static function renderGenericError(\Exception $e) {
// Render generic error page
}
}
?>Application Bootstrap
Bootstrap File
php
<?php
// bootstrap.php
// Define constants
define('ROOT_PATH', __DIR__);
define('APP_PATH', ROOT_PATH . '/src');
define('CONFIG_PATH', ROOT_PATH . '/config');
// Load environment variables
if (file_exists(ROOT_PATH . '/.env')) {
$lines = file(ROOT_PATH . '/.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos($line, '=') !== false && strpos($line, '#') !== 0) {
list($key, $value) = explode('=', $line, 2);
$_ENV[trim($key)] = trim($value);
}
}
}
// Autoloader
require_once ROOT_PATH . '/vendor/autoload.php';
// Error handling
use App\Core\ErrorHandler;
ErrorHandler::register();
// Load configuration
use App\Core\Config;
Config::load('app');
Config::load('database');
// Set error reporting based on environment
if (Config::get('app.debug')) {
error_reporting(E_ALL);
ini_set('display_errors', 1);
} else {
error_reporting(0);
ini_set('display_errors', 0);
}
?>下一步
现在您已经了解了如何构建PHP程序,让我们在数据类型中详细探讨PHP的数据类型。
实践练习
- 创建一个具有适当命名空间组织的多文件项目
- 为博客应用程序实现简单的MVC结构
- 为您的自定义类设置自动加载
- 创建一个支持不同环境的配置系统
- 构建一个带有自定义异常的基本错误处理系统
理解程序结构对于构建可维护的PHP应用程序至关重要!