强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 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 提供了一组预定义的超全局变量,在任何作用域中都可直接访问:

变量说明
$_GETURL 查询参数
$_POSTPOST 表单数据
$_REQUESTGET + POST + COOKIE(不推荐使用)
$_SERVER服务器和请求信息
$_FILES文件上传
$_COOKIECookie 数据
$_SESSIONSession 数据
$_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 章 — 变量与类型