Skip to content

基础交互脚本

本节将带你从零开始编写第一个 PHP 脚本。你将学习如何创建 PHP 文件、使用 PHP 标签、向浏览器输出内容、定义和使用变量、进行字符串操作以及使用注释。这些是 PHP 编程最基础的知识,也是后续学习所有高级特性的基石。

前置知识

在开始本节之前,你需要:

  • 已安装 PHP 8.1 或更高版本(运行 php -v 检查版本)
  • 有一个代码编辑器(推荐 VS Code、PHPStorm 或 Sublime Text)
  • 了解基本的 HTML 知识(了解 HTML 标签的作用)

基础概念

创建第一个 PHP 文件

PHP 文件本质上是一个文本文件,使用 .php 扩展名。你可以在任何文本编辑器中创建 PHP 文件。创建一个名为 hello.php 的文件,内容如下:

php
<?php
declare(strict_types=1);

echo "Hello, World!";

保存文件后,你可以通过以下两种方式之一来运行它:

方式一:命令行运行

bash
php hello.php

方式二:使用 PHP 内置 Web 服务器

bash
php -S localhost:8000

然后在浏览器中访问 http://localhost:8000/hello.php

PHP 内置服务器

PHP 自 5.4 起内置了一个轻量级的 Web 服务器,非常适合开发和测试。不过它不适合用于生产环境。使用 php -S localhost:8000 启动服务器,然后在该目录下的所有 .php 文件都可以通过浏览器访问。

PHP 标签的使用

标准 PHP 标签

PHP 代码必须包含在 PHP 标签内。最常用且最推荐的是标准标签:

php
<?php
declare(strict_types=1);

// 在这里编写 PHP 代码

// PHP 文件的末尾不要添加闭合标签 ?>

关于 PHP 文件末尾是否添加 ?> 闭合标签,PHP 社区的共识是不要添加。原因是 PHP 标签之后如果有多余的空行或空白字符,可能会导致 headers already sent 错误。

短回显标签

短回显标签 <?= ?> 自 PHP 5.4 起始终可用(无需在 php.ini 中配置),它是 <?php echo ?> 的简写:

php
<?php
declare(strict_types=1);

$name = 'PHP Developer';
$year = 2024;
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>短回显标签示例</title>
</head>
<body>
    <!-- 以下两种写法等价 -->
    <p>方式一:<?= htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?></p>
    <p>方式二:<?php echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8'); ?></p>
    <p>当前年份:<?= $year ?></p>
</body>
</html>

避免使用短标签

PHP 的短标签 <?(不是 <?=)需要在 php.ini 中启用 short_open_tag = On,且在现代 PHP 开发中不推荐使用。始终使用标准的 <?php 标签。

输出到浏览器

echo 和 print

echoprint 是 PHP 中最常用的输出语句。两者都可以输出字符串,但有细微区别:

特性echoprint
语言结构
返回值无(void)始终返回 1
速度略快略慢
多参数支持支持 echo 'a', 'b'不支持
php
<?php
declare(strict_types=1);

// echo — 最常用的输出方式
echo "Hello, World!\n";        // 输出字符串
echo "PHP 版本: ", PHP_VERSION, "\n"; // echo 可以用逗号连接多个参数

// print — 类似 echo,但返回 1
$result = print "使用 print 输出\n";
echo "print 的返回值: {$result}\n"; // 输出 1

// 输出变量的值
$language = 'PHP';
$version = 8.3;
echo "学习 {$language} {$version}\n";

// 使用 Heredoc 语法输出多行文本(PHP 7.3+ 灵活 Heredoc)
$html = <<<HTML
<div class="card">
    <h2>欢迎学习 PHP</h2>
    <p>这是使用 Heredoc 语法输出的多行 HTML 内容。</p>
</div>
HTML;

echo $html . "\n";

// 使用 Nowdoc 语法输出纯文本(不解析变量)
$text = <<<'TEXT'
这是一段纯文本,
不会解析 $language 和 $version 变量。
显示原始的 $ 符号。
TEXT;

echo $text . "\n";

printf 和 sprintf 格式化输出

当你需要精确控制输出格式时,可以使用 printf 系列函数:

php
<?php
declare(strict_types=1);

// printf — 格式化并直接输出
printf("整数: %d\n", 42);
printf("浮点数: %.2f\n", 3.14159);
printf("字符串: %s\n", 'Hello PHP');
printf("八进制: %o\n", 255);
printf("十六进制: %x\n", 255);
printf("科学计数: %e\n", 1000000);

// sprintf — 格式化为字符串(不直接输出)
$price = 99.50;
$quantity = 3;
$formatted = sprintf("商品价格: ¥%.2f x %d = ¥%.2f", $price, $quantity, $price * $quantity);
echo $formatted . "\n";

// 表格化的格式化输出
$products = [
    ['name' => 'PHP 入门', 'price' => 49.90],
    ['name' => 'MySQL 实战', 'price' => 69.90],
    ['name' => 'Laravel 框架', 'price' => 89.90],
];

echo str_repeat('-', 40) . "\n";
printf("%-20s %10s\n", '商品名称', '价格');
echo str_repeat('-', 40) . "\n";

foreach ($products as $product) {
    printf("%-20s %10.2f\n", $product['name'], $product['price']);
}

echo str_repeat('-', 40) . "\n";

变量的基本使用

变量声明与赋值

PHP 中的变量以 $ 符号开头,后跟变量名。PHP 是弱类型语言,变量不需要预先声明类型,但推荐使用类型声明来增强代码的安全性:

php
<?php
declare(strict_types=1);

// 基本变量赋值
$username = '张三';
$age = 30;
$salary = 15000.50;
$isEmployed = true;
$skills = ['PHP', 'MySQL', 'Redis'];

// PHP 7.4+ 支持属性提升语法,PHP 8.0+ 支持构造器属性提升
// 以下是现代 PHP 的变量使用方式

// 类型化变量(通过赋值间接声明)
function demonstrateTypes(): void
{
    $integerValue = 42;           // int
    $floatValue = 3.14;           // float
    $stringValue = 'Hello';       // string
    $booleanValue = true;         // bool
    $nullValue = null;            // null
    $arrayValue = [1, 2, 3];      // array

    // 使用 get_debug_info 查看类型
    echo "integer: {$integerValue} (类型: " . get_debug_type($integerValue) . ")\n";
    echo "float: {$floatValue} (类型: " . get_debug_type($floatValue) . ")\n";
    echo "string: {$stringValue} (类型: " . get_debug_type($stringValue) . ")\n";
    echo "bool: " . ($booleanValue ? 'true' : 'false') . " (类型: " . get_debug_type($booleanValue) . ")\n";
    echo "null: (类型: " . get_debug_type($nullValue) . ")\n";
    echo "array: (类型: " . get_debug_type($arrayValue) . ")\n";
}

demonstrateTypes();

变量作用域

PHP 有不同的变量作用域:全局作用域、函数作用域(局部)、静态变量和超全局变量:

php
<?php
declare(strict_types=1);

// 变量作用域演示

$globalVariable = '我是全局变量';

function scopeDemo(): void
{
    // 函数内部无法直接访问全局变量
    // echo $globalVariable; // 会出现 Undefined variable 警告

    // 使用 global 关键字引入全局变量(不推荐)
    // global $globalVariable;
    // echo $globalVariable;

    // 推荐:通过参数传递
}

// 静态变量 — 函数调用之间保持值
function counter(): int
{
    static $count = 0;
    $count++;
    return $count;
}

echo "静态变量演示:\n";
echo counter() . "\n"; // 1
echo counter() . "\n"; // 2
echo counter() . "\n"; // 3

// 超全局变量 — 在任何作用域都可访问
function showSuperGlobals(): void
{
    echo "\n超全局变量:\n";
    echo "PHP 版本: " . PHP_VERSION . "\n";
    echo "SAPI 类型: " . PHP_SAPI . "\n";

    if (PHP_SAPI === 'cli') {
        echo "命令行参数数: " . count($_SERVER['argv'] ?? []) . "\n";
    }
}

showSuperGlobals();

// PHP 8.1+ 可以使用 readonly 属性实现不可变值
class AppConfig
{
    public function __construct(
        public readonly string $appName,
        public readonly string $environment,
        public readonly bool $debug = false
    ) {
    }

    // 静态工厂方法
    public static function fromArray(array $config): self
    {
        return new self(
            appName: $config['app_name'],
            environment: $config['environment'],
            debug: $config['debug'] ?? false,
        );
    }
}

$config = new AppConfig(appName: 'MyApp', environment: 'development', debug: true);
echo "\n应用名称: {$config->appName}\n";
echo "环境: {$config->environment}\n";
echo "调试模式: " . ($config->debug ? '开启' : '关闭') . "\n";

字符串拼接

字符串操作

PHP 提供了多种字符串拼接和操作方式:

php
<?php
declare(strict_types=1);

// 字符串拼接方式

// 1. 使用点号(.)运算符
$firstName = '张';
$lastName = '三';
$fullName = $firstName . $lastName;
echo "点号拼接: {$fullName}\n";

// 2. 使用双引号内插变量(推荐用于简单场景)
$greeting = "你好,{$fullName}!";
echo "变量内插: {$greeting}\n";

// 3. 使用双引号内插复杂表达式(使用花括号)
$price = 99.50;
$quantity = 3;
$total = $price * $quantity;
echo "计算内插: 总价 {$price} x {$quantity} = {$total}\n";

// 4. 使用 implode 连接数组元素
$tags = ['PHP', '教程', '入门'];
$tagString = implode(', ', $tags);
echo "数组拼接: {$tagString}\n";

// 5. 使用 sprintf 格式化字符串
$info = sprintf('姓名: %s, 年龄: %d, 邮箱: %s', '李四', 28, 'lisi@example.com');
echo "格式化: {$info}\n";

// PHP 8.0+ 新增的字符串函数
$needle = 'PHP';
$haystack = 'Welcome to PHP Tutorial';

// str_contains — 检查字符串是否包含子串
echo "\n=== PHP 8.0+ 字符串函数 ===\n";
echo "'{$haystack}' 包含 '{$needle}': " . (str_contains($haystack, $needle) ? '是' : '否') . "\n";

// str_starts_with — 检查是否以指定字符串开头
echo "以 'Welcome' 开头: " . (str_starts_with($haystack, 'Welcome') ? '是' : '否') . "\n";

// str_ends_with — 检查是否以指定字符串结尾
echo "以 'Tutorial' 结尾: " . (str_ends_with($haystack, 'Tutorial') ? '是' : '否') . "\n";

// 字符串长度与编码
$chineseStr = '你好,世界!';
echo "\n中文字符串长度:\n";
echo "strlen: " . strlen($chineseStr) . " 字节\n";  // 返回字节数
echo "mb_strlen: " . mb_strlen($chineseStr, 'UTF-8') . " 字符\n"; // 返回字符数

// 字符串截取
echo "mb_substr: " . mb_substr($chineseStr, 0, 3, 'UTF-8') . "\n";

// 字符串替换
$template = 'Dear {name}, your order #{orderId} has been shipped.';
$replaced = str_replace(
    ['{name}', '{orderId}'],
    ['张三', '20240001'],
    $template
);
echo "字符串替换: {$replaced}\n";

多行字符串

PHP 提供了多种处理多行字符串的方式:

php
<?php
declare(strict_types=1);

// Heredoc — 解析变量和转义字符(PHP 7.3+ 灵活语法)
$name = 'PHP 开发者';
$htmlBlock = <<<HTML
<!DOCTYPE html>
<html>
<head>
    <title>欢迎, {$name}</title>
</head>
<body>
    <h1>Hello, {$name}</h1>
</body>
</html>
HTML;

echo "Heredoc 输出:\n{$htmlBlock}\n\n";

// Nowdoc — 不解析变量(纯文本)
$rawText = <<<'TEXT'
这是一个 Nowdoc 示例。
变量名 {$name} 会被原样输出。
不解析任何特殊字符。
TEXT;

echo "Nowdoc 输出:\n{$rawText}\n";

注释的使用

PHP 支持三种注释方式:

php
<?php
declare(strict_types=1);

/**
 * 这是一个文档注释(DocBlock)
 *
 * 用于描述类、方法、函数的用途和用法
 * 可以使用 PHPDoc 标签提供额外信息
 *
 * @param string $name 用户名
 * @param int $age 年龄
 * @return array 用户信息数组
 */
function createUser(string $name, int $age): array
{
    // 这是单行注释 — 用于解释单行代码
    return [
        'name' => $name,
        'age' => $age,
    ];
}

/*
 * 这是多行注释
 * 适用于较长的注释内容
 * 可以跨越多行
 */

// PHP 8.0+ 属性(Attributes)可以替代部分注释
#[\Deprecated(message: '请使用 newUser 函数代替', since: '2.0')]
function oldCreateUser(string $name): array
{
    return ['name' => $name];
}

// 注释的最佳实践:
// 1. 解释「为什么」这样做,而不是「做了什么」
// 2. 保持注释与代码同步
// 3. 复杂逻辑处添加注释
// 4. TODO 注释标记待完成的工作
// TODO: 添加用户验证逻辑
// FIXME: 处理空用户名的情况
// NOTE: 此函数仅在 CLI 模式下可用

简单的计算示例

运算符

PHP 提供了丰富的运算符来执行各种计算:

php
<?php
declare(strict_types=1);

// ========== 算术运算符 ==========
echo "=== 算术运算符 ===\n";
$a = 20;
$b = 7;

echo "a = {$a}, b = {$b}\n";
echo "a + b = " . ($a + $b) . "\n";    // 加法: 27
echo "a - b = " . ($a - $b) . "\n";    // 减法: 13
echo "a * b = " . ($a * $b) . "\n";    // 乘法: 140
echo "a / b = " . ($a / $b) . "\n";    // 除法: 2.857...
echo "a % b = " . ($a % $b) . "\n";    // 取模: 6
echo "a ** b = " . ($a ** $b) . "\n";  // 幂运算 (PHP 5.6+): 1280000000

// ========== 赋值运算符 ==========
echo "\n=== 赋值运算符 ===\n";
$total = 100;
$total += 50;   // $total = $total + 50
echo "加等: {$total}\n";
$total -= 30;   // $total = $total - 30
echo "减等: {$total}\n";
$total *= 2;    // $total = $total * 2
echo "乘等: {$total}\n";
$total /= 4;    // $total = $total / 4
echo "除等: {$total}\n";

// Null 合并赋值运算符(PHP 7.4+)
$config = [];
$config['timeout'] ??= 30;  // 如果 key 不存在则赋默认值
echo "超时设置: {$config['timeout']}\n";

// ========== 比较运算符 ==========
echo "\n=== 比较运算符 ===\n";
$x = 10;
$y = '10';
echo "x = {$x} (int), y = {$y} (string)\n";
echo "x == y: " . ($x == $y ? 'true' : 'false') . "\n";   // true(松散比较)
echo "x === y: " . ($x === $y ? 'true' : 'false') . "\n";  // false(严格比较)
echo "x <=> y: " . ($x <=> $y) . "\n";                     // 0(太空船运算符,PHP 7+)

// ========== 逻辑运算符 ==========
echo "\n=== 逻辑运算符 ===\n";
$isAdmin = true;
$hasPermission = false;

echo "isAdmin && hasPermission: " . ($isAdmin && $hasPermission ? 'true' : 'false') . "\n";
echo "isAdmin || hasPermission: " . ($isAdmin || $hasPermission ? 'true' : 'false') . "\n";
echo "!isAdmin: " . (!$isAdmin ? 'true' : 'false') . "\n";

// ========== 三元运算符与 Null 合并运算符 ==========
echo "\n=== 三元与 Null 合并 ===\n";
$username = null;
$displayName = $username ?? '匿名用户';
echo "显示名称: {$displayName}\n";

$status = 200;
$statusText = $status >= 200 && $status < 300 ? '成功' : '失败';
echo "状态: {$statusText}\n";

// 嵌套三元运算符(PHP 8.0+ 的 match 表达式更好)
$role = 'editor';
$accessLevel = match ($role) {
    'admin' => '完全访问',
    'editor' => '编辑访问',
    'viewer' => '只读访问',
    default => '无权限',
};
echo "角色 '{$role}' 的权限: {$accessLevel}\n";

实用的计算工具

php
<?php
declare(strict_types=1);

/**
 * 简单的计算器工具类
 * 展示 PHP 中函数、类型声明和运算符的综合使用
 */
class Calculator
{
    // 四则运算
    public static function add(float|int $a, float|int $b): float
    {
        return (float) ($a + $b);
    }

    public static function subtract(float|int $a, float|int $b): float
    {
        return (float) ($a - $b);
    }

    public static function multiply(float|int $a, float|int $b): float
    {
        return (float) ($a * $b);
    }

    public static function divide(float|int $a, float|int $b): float
    {
        if ($b == 0) {
            throw new \DivisionByZeroError('除数不能为零');
        }
        return (float) ($a / $b);
    }

    // 平均值
    public static function average(float|int ...$numbers): float
    {
        if (count($numbers) === 0) {
            throw new \InvalidArgumentException('至少需要一个数字');
        }
        $sum = array_sum($numbers);
        return $sum / count($numbers);
    }

    // 温度转换
    public static function celsiusToFahrenheit(float $celsius): float
    {
        return $celsius * 9 / 5 + 32;
    }

    public static function fahrenheitToCelsius(float $fahrenheit): float
    {
        return ($fahrenheit - 32) * 5 / 9;
    }

    // BMI 计算
    public static function calculateBmi(float $weightKg, float $heightM): array
    {
        if ($heightM <= 0) {
            throw new \InvalidArgumentException('身高必须大于 0');
        }
        $bmi = $weightKg / ($heightM ** 2);

        $category = match (true) {
            $bmi < 18.5 => '偏瘦',
            $bmi < 24.0 => '正常',
            $bmi < 28.0 => '偏胖',
            default => '肥胖',
        };

        return [
            'bmi' => round($bmi, 1),
            'category' => $category,
        ];
    }
}

// 使用示例
echo "=== 计算器工具 ===\n\n";

// 四则运算
echo "10 + 3 = " . Calculator::add(10, 3) . "\n";
echo "10 - 3 = " . Calculator::subtract(10, 3) . "\n";
echo "10 * 3 = " . Calculator::multiply(10, 3) . "\n";
echo "10 / 3 = " . Calculator::divide(10, 3) . "\n";

// 平均值
$scores = [85, 92, 78, 95, 88];
$avg = Calculator::average(...$scores);
echo "\n成绩平均分: {$avg}\n";

// 温度转换
$celsius = 36.5;
$fahrenheit = Calculator::celsiusToFahrenheit($celsius);
echo "\n{$celsius} C = {$fahrenheit} F\n";

// BMI 计算
$bmiResult = Calculator::calculateBmi(70, 1.75);
echo "\nBMI 计算结果: {$bmiResult['bmi']} ({$bmiResult['category']})\n";

实战示例

个人信息展示脚本

php
<?php
declare(strict_types=1);

/**
 * 个人信息展示脚本
 * 综合运用变量、字符串操作、运算符和输出功能
 */

class Person
{
    public function __construct(
        public readonly string $name,
        public readonly int $age,
        public readonly string $email,
        public readonly array $skills,
        public readonly string $city = '北京',
        public readonly bool $isEmployed = true
    ) {
    }

    public function getAgeDescription(): string
    {
        return match (true) {
            $this->age < 18 => '未成年',
            $this->age < 30 => '青年',
            $this->age < 50 => '中年',
            default => '老年',
        };
    }

    public function getSkillLevel(): string
    {
        $count = count($this->skills);
        return match (true) {
            $count < 3 => '初级开发者',
            $count < 6 => '中级开发者',
            $count < 10 => '高级开发者',
            default => '资深开发者',
        };
    }

    public function toHtml(): string
    {
        $escapedName = htmlspecialchars($this->name, ENT_QUOTES, 'UTF-8');
        $escapedEmail = htmlspecialchars($this->email, ENT_QUOTES, 'UTF-8');
        $escapedCity = htmlspecialchars($this->city, ENT_QUOTES, 'UTF-8');
        $skillList = implode(', ', array_map(
            fn($skill) => htmlspecialchars($skill, ENT_QUOTES, 'UTF-8'),
            $this->skills
        ));

        return <<<HTML
<div class="person-card">
    <h2>{$escapedName}</h2>
    <ul>
        <li>年龄: {$this->age} 岁 ({$this->getAgeDescription()})</li>
        <li>邮箱: {$escapedEmail}</li>
        <li>城市: {$escapedCity}</li>
        <li>状态: {$this->isEmployed ? '在职' : '求职中'}</li>
        <li>技能: {$skillList}</li>
        <li>等级: {$this->getSkillLevel()}</li>
    </ul>
</div>
HTML;
    }

    public function toText(): string
    {
        $separator = str_repeat('-', 40);
        $lines = [
            $separator,
            "姓名: {$this->name}",
            "年龄: {$this->age} 岁 ({$this->getAgeDescription()})",
            "邮箱: {$this->email}",
            "城市: {$this->city}",
            "状态: " . ($this->isEmployed ? '在职' : '求职中'),
            "技能: " . implode(', ', $this->skills),
            "等级: {$this->getSkillLevel()}",
            $separator,
        ];
        return implode("\n", $lines);
    }
}

// 创建个人信息
$person = new Person(
    name: '李明',
    age: 28,
    email: 'liming@example.com',
    skills: ['PHP', 'MySQL', 'Redis', 'Laravel', 'Docker', 'Linux'],
    city: '上海'
);

// 根据运行环境选择输出格式
if (PHP_SAPI === 'cli') {
    echo $person->toText() . "\n";
} else {
    header('Content-Type: text/html; charset=UTF-8');
    echo <<<HTML
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>个人信息</title>
        <style>
            body { font-family: sans-serif; padding: 20px; background: #f5f5f5; }
            .person-card { background: white; padding: 20px; border-radius: 8px; max-width: 400px; }
            .person-card h2 { margin-top: 0; color: #333; }
            .person-card ul { list-style: none; padding: 0; }
            .person-card li { padding: 8px 0; border-bottom: 1px solid #eee; }
        </style>
    </head>
    <body>
        {$person->toHtml()}
    </body>
    </html>
HTML;
}

注意事项

  • PHP 标签顺序declare(strict_types=1) 必须是 <?php 标签之后的第一条语句,否则会抛出致命错误。
  • 变量命名:变量名区分大小写($Name$name 是不同的变量),但函数名和类名不区分大小写。
  • 字符串引号:双引号解析变量和转义字符,单引号不解析变量。性能差异极小,但语义不同。
  • 未定义变量:访问未定义的变量会产生警告,使用 isset()?? 运算符来避免。
  • 文件末尾:不要在 PHP 文件末尾添加闭合标签 ?>,以防止意外的空白输出。
  • 编码问题:始终使用 UTF-8 编码保存 PHP 文件,处理中文字符时使用 mb_* 系列函数。

最佳实践

  • 每个 PHP 文件都以 <?phpdeclare(strict_types=1); 开始。
  • 使用有意义的变量名,遵循驼峰命名法(如 $userName$orderTotal)。
  • 在字符串中使用变量内插(双引号)而不是拼接,提高可读性。
  • 使用 match 表达式替代 switch 语句,更安全更简洁。
  • 复杂字符串使用 Heredoc/Nowdoc 语法,避免转义地狱。
  • 注释解释「为什么」,代码表达「做什么」。
  • 使用 PHPStorm 或 VS Code 的 PHP 插件来获得代码补全和错误提示。

下一节

掌握了 PHP 的基础语法之后,让我们进入实际应用场景。下一节 表单处理 将教你如何用 PHP 处理用户通过 HTML 表单提交的数据。

参考链接