基础交互脚本
本节将带你从零开始编写第一个 PHP 脚本。你将学习如何创建 PHP 文件、使用 PHP 标签、向浏览器输出内容、定义和使用变量、进行字符串操作以及使用注释。这些是 PHP 编程最基础的知识,也是后续学习所有高级特性的基石。
前置知识
在开始本节之前,你需要:
- 已安装 PHP 8.1 或更高版本(运行
php -v检查版本) - 有一个代码编辑器(推荐 VS Code、PHPStorm 或 Sublime Text)
- 了解基本的 HTML 知识(了解 HTML 标签的作用)
基础概念
创建第一个 PHP 文件
PHP 文件本质上是一个文本文件,使用 .php 扩展名。你可以在任何文本编辑器中创建 PHP 文件。创建一个名为 hello.php 的文件,内容如下:
<?php
declare(strict_types=1);
echo "Hello, World!";保存文件后,你可以通过以下两种方式之一来运行它:
方式一:命令行运行
php hello.php方式二:使用 PHP 内置 Web 服务器
php -S localhost:8000然后在浏览器中访问 http://localhost:8000/hello.php。
PHP 内置服务器
PHP 自 5.4 起内置了一个轻量级的 Web 服务器,非常适合开发和测试。不过它不适合用于生产环境。使用 php -S localhost:8000 启动服务器,然后在该目录下的所有 .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
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
echo 和 print 是 PHP 中最常用的输出语句。两者都可以输出字符串,但有细微区别:
| 特性 | echo | print |
|---|---|---|
| 语言结构 | 是 | 是 |
| 返回值 | 无(void) | 始终返回 1 |
| 速度 | 略快 | 略慢 |
| 多参数支持 | 支持 echo 'a', 'b' | 不支持 |
<?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
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
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
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
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
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
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
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
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
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 文件都以
<?php和declare(strict_types=1);开始。 - 使用有意义的变量名,遵循驼峰命名法(如
$userName、$orderTotal)。 - 在字符串中使用变量内插(双引号)而不是拼接,提高可读性。
- 使用
match表达式替代switch语句,更安全更简洁。 - 复杂字符串使用 Heredoc/Nowdoc 语法,避免转义地狱。
- 注释解释「为什么」,代码表达「做什么」。
- 使用 PHPStorm 或 VS Code 的 PHP 插件来获得代码补全和错误提示。
下一节
掌握了 PHP 的基础语法之后,让我们进入实际应用场景。下一节 表单处理 将教你如何用 PHP 处理用户通过 HTML 表单提交的数据。