第 3 章 — Hello World
第 3 章 — Hello World:内置服务器与项目结构
3.1 第一个 PHP 脚本
创建一个最简单的 PHP 文件:
<?php
// hello.php
declare(strict_types=1); // 推荐:开启严格类型模式
echo "Hello, World!\n";
// 多种输出方式
print "Hello again!\n";
printf("Hello, %s! You are %d years old.\n", 'Alice', 25);
echo sprintf("PI is approximately %.2f\n", 3.14159);
运行:
php hello.php
# 输出:
# Hello, World!
# Hello again!
# Hello, Alice! You are 25 years old.
# PI is approximately 3.14
3.2 PHP 内置开发服务器
PHP 5.4+ 内置了一个 Web 服务器,非常适合本地开发:
# 最简启动方式(在项目根目录)
php -S localhost:8000
# 指定文档根目录
php -S localhost:8000 -t public/
# 指定 IP 和端口
php -S 0.0.0.0:8080 -t public/
3.2.1 路由脚本
内置服务器支持路由脚本,用于实现 URL 重写:
<?php
// router.php — 路由脚本
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
// 静态文件直接返回 false(由内置服务器处理)
if (file_exists(__DIR__ . '/public' . $uri)) {
return false;
}
// 路由分发
match ($uri) {
'/' => require __DIR__ . '/src/pages/home.php',
'/about' => require __DIR__ . '/src/pages/about.php',
'/api/time' => handleApiTime(),
default => http_response_code(404) && print('404 Not Found'),
};
function handleApiTime(): void
{
header('Content-Type: application/json');
echo json_encode([
'time' => date('Y-m-d H:i:s'),
'timezone' => date_default_timezone_get(),
], JSON_PRETTY_PRINT);
}
# 使用路由脚本启动
php -S localhost:8000 router.php
3.3 推荐项目结构
3.3.1 小型项目
my-project/
├── public/ # Web 可访问的根目录
│ ├── index.php # 前端控制器(单一入口)
│ ├── .htaccess # Apache URL 重写规则
│ └── assets/ # CSS、JS、图片
├── src/ # 源码
│ ├── Controller/
│ ├── Model/
│ └── Service/
├── templates/ # 模板文件
├── config/ # 配置文件
├── storage/ # 日志、缓存、上传文件
├── tests/ # 测试
├── composer.json
└── .env # 环境变量
3.3.2 单一入口模式
<?php
// public/index.php — 前端控制器
declare(strict_types=1);
// 加载 Composer 自动加载器
require_once dirname(__DIR__) . '/vendor/autoload.php';
// 加载 .env
$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__));
$dotenv->load();
// 简单路由分发
$uri = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
header('Content-Type: text/html; charset=utf-8');
echo "<!DOCTYPE html>
<html>
<head><title>My PHP App</title></head>
<body>
<h1>欢迎来到我的 PHP 应用</h1>
<p>请求路径: {$uri}</p>
<p>请求方法: {$method}</p>
<p>PHP 版本: " . PHP_VERSION . "</p>
<p>服务器时间: " . date('Y-m-d H:i:s') . "</p>
</body>
</html>";
3.3.3 Apache .htaccess
# public/.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
3.3.4 Nginx 配置
server {
listen 80;
server_name localhost;
root /var/www/my-project/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
3.4 基本输出与 HTML 混合
<?php
// templates/page.php
$title = "我的页面";
$items = ['PHP', 'MySQL', 'Redis', 'Docker'];
?>
<!DOCTYPE html>
<html lang="zh-chs">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars($title) ?></title>
</head>
<body>
<h1><?= htmlspecialchars($title) ?></h1>
<h2>技术栈</h2>
<ul>
<?php foreach ($items as $item): ?>
<li><?= htmlspecialchars($item) ?></li>
<?php endforeach; ?>
</ul>
<footer>
<p>生成时间: <?= date('Y-m-d H:i:s') ?></p>
<p>PHP <?= PHP_VERSION ?></p>
</footer>
</body>
</html>
安全提示:在模板中输出变量时,始终使用
htmlspecialchars()防止 XSS 攻击。
3.5 超全局变量(Superglobals)
PHP 提供了一组预定义的超全局变量,在任何作用域中都可直接访问:
| 变量 | 说明 |
|---|---|
$_GET | URL 查询参数 |
$_POST | POST 表单数据 |
$_REQUEST | GET + POST + COOKIE(不推荐使用) |
$_SERVER | 服务器和请求信息 |
$_FILES | 文件上传 |
$_COOKIE | Cookie 数据 |
$_SESSION | Session 数据 |
$_ENV | 环境变量 |
$GLOBALS | 所有全局变量 |
$_SERVER 常用键
<?php
echo $_SERVER['REQUEST_METHOD']; // GET, POST, ...
echo $_SERVER['REQUEST_URI']; // /path?query=1
echo $_SERVER['HTTP_HOST']; // example.com
echo $_SERVER['HTTP_USER_AGENT']; // Mozilla/5.0 ...
echo $_SERVER['REMOTE_ADDR']; // 127.0.0.1
echo $_SERVER['SERVER_NAME']; // localhost
echo $_SERVER['SERVER_PORT']; // 80
echo $_SERVER['HTTPS']; // on 或空
3.6 表单处理示例
<?php
// public/contact.php
declare(strict_types=1);
$errors = [];
$success = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$message = trim($_POST['message'] ?? '');
if ($name === '') {
$errors[] = '姓名不能为空';
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = '邮箱格式不正确';
}
if ($message === '') {
$errors[] = '留言不能为空';
}
if (empty($errors)) {
// 实际项目中这里会发送邮件或保存到数据库
$success = true;
}
}
?>
<!DOCTYPE html>
<html lang="zh-chs">
<head><meta charset="UTF-8"><title>联系我们</title></head>
<body>
<h1>联系我们</h1>
<?php if ($success): ?>
<p style="color: green;">✅ 消息已发送!</p>
<?php endif; ?>
<?php if (!empty($errors)): ?>
<ul style="color: red;">
<?php foreach ($errors as $error): ?>
<li><?= htmlspecialchars($error) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<form method="POST">
<div>
<label>姓名: <input type="text" name="name"
value="<?= htmlspecialchars($name ?? '') ?>"></label>
</div>
<div>
<label>邮箱: <input type="email" name="email"
value="<?= htmlspecialchars($email ?? '') ?>"></label>
</div>
<div>
<label>留言: <textarea name="message"><?= htmlspecialchars($message ?? '') ?></textarea></label>
</div>
<button type="submit">提交</button>
</form>
</body>
</html>
3.7 CLI 模式基础
PHP 不仅可以用于 Web,还能编写命令行工具:
#!/usr/bin/env php
<?php
// bin/greet.php — 命令行工具
declare(strict_types=1);
// 命令行参数
$name = $argv[1] ?? 'World';
// 标准输出
fwrite(STDOUT, "Hello, {$name}!\n");
// 标准错误
fwrite(STDERR, "Debug: script executed at " . date('Y-m-d H:i:s') . "\n");
// 读取用户输入
fwrite(STDOUT, "What's your favorite language? ");
$answer = trim(fgets(STDIN));
echo "You said: {$answer}\n";
// 退出码
exit(0); // 0 = 成功, 非 0 = 失败
# 运行 CLI 脚本
php bin/greet.php Alice
# 或
chmod +x bin/greet.php
./bin/greet.php Alice
3.8 业务场景:快速原型开发
当需要快速验证一个 Web 功能时,PHP 内置服务器是最高效的方案:
# 1. 创建项目
mkdir demo && cd demo
# 2. 安装依赖
composer require vlucas/phpdotenv
# 3. 创建入口
mkdir public
cat > public/index.php << 'EOF'
<?php
require __DIR__ . '/../vendor/autoload.php';
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
match ($path) {
'/' => include __DIR__ . '/../src/home.php',
'/api/users' => include __DIR__ . '/../src/api_users.php',
default => http_response_code(404) . print('Not Found'),
};
EOF
# 4. 启动
php -S localhost:8000 -t public/
从创建项目到看到页面,不超过 2 分钟。
3.9 扩展阅读
上一章:第 2 章 — 环境安装 下一章:第 4 章 — 变量与类型