编码 · 编程语言
PHP 入门教程(零基础)
简短回答
PHP 是专为 Web 而生的服务器端脚本语言:PHP 文件在服务器上运行,并向浏览器发送 HTML 或 JSON。安装 PHP,把 <?php echo "Hello, world"; 保存为 hello.php 并运行 php hello.php,或用 php -S localhost:8000 启动本地服务器。核心概念包括:以 $ 开头的变量、灵活的数组、带类型声明的函数、类、异常,以及对用户输入的安全处理。
PHP 是什么,用来做什么
PHP 由 Rasmus Lerdorf 于 1994 年创建;如今这个名字代表“PHP: Hypertext Preprocessor”。几乎所有虚拟主机都支持 PHP,大量网站由它驱动,包括 WordPress、Drupal 和维基百科使用的 MediaWiki。开发者用它构建内容网站、网上商店、REST API,以及借助 Laravel 和 Symfony 等框架开发完整的 Web 应用。现代 PHP 8 拥有类型系统、JIT 编译器、枚举、属性(attributes),性能也比旧版本好得多。
安装 PHP 并运行 Hello, world
从 php.net 或通过包管理器安装 PHP(brew install php、sudo apt install php-cli,或在 Windows 上使用 XAMPP 等集成包)。用 php -v 检查。PHP 代码写在 <?php 与可选的结束标记 ?> 之间。
<?php
echo "Hello, world\n";php hello.php
# Hello, world
php -S localhost:8000 # serve the current folder at http://localhost:8000在只含 PHP 代码的文件中,请省略结束标记 ?>,以免意外向浏览器发送多余的空白字符。
变量与基本类型
变量名以 $ 开头。类型是动态的,但你可以声明参数类型和返回类型;在文件顶部写 declare(strict_types=1); 可以禁止函数调用中的自动类型转换。
| 类型 | 示例 | 说明 |
|---|---|---|
int | $n = 42; | 大多数系统上为 64 位 |
float | $x = 3.14; | 双精度 |
string | $s = "hi $name"; | 双引号会插值,单引号不会 |
bool | $ok = true; | 关键字不区分大小写 |
array | $a = [1, 2]; | 有序映射:同时是列表和字典 |
null | $v = null; | 没有值 |
<?php
$name = "Ada";
$count = 7;
echo "$name has $count items\n"; // Ada has 7 items
echo 'No $interpolation here' . "\n"; // No $interpolation here
echo intdiv($count, 2), " ", $count / 2, "\n"; // 3 3.5
var_dump((int) "12" + 1); // int(13). 运算符用于连接字符串;+ 只用于数字。
流程控制
<?php
$score = 72;
if ($score >= 90) {
echo "A\n";
} elseif ($score >= 70) {
echo "B\n"; // B
} else {
echo "C\n";
}
for ($i = 0; $i < 3; $i++) {
echo $i, " "; // 0 1 2
}
echo "\n";
foreach (["apple", "pear"] as $fruit) {
echo $fruit, "\n";
}
$kind = match ($day = "SAT") { // match is strict and returns a value
"SAT", "SUN" => "weekend",
default => "weekday",
};
echo $kind, "\n"; // weekendmatch(PHP 8.0 及以上)使用 === 比较,没有分支匹配时会抛出错误;而旧的 switch 使用宽松比较,并且没有 break 时会继续向下执行。
函数
<?php
declare(strict_types=1);
function greet(string $name, string $greeting = "Hello"): string
{
return "$greeting, $name!";
}
echo greet("Lin"), "\n"; // Hello, Lin!
echo greet(greeting: "Hi", name: "Lin"), "\n"; // Hi, Lin! (named arguments)
$square = fn(int $x): int => $x * $x; // arrow function
echo $square(5), "\n"; // 25
function total(int ...$nums): int // variadic
{
return array_sum($nums);
}
echo total(1, 2, 3), "\n"; // 6标志性特性:数组
PHP 数组是一种灵活的类型,可以用作列表、字典、栈或队列。键是整数或字符串,并且保持插入顺序。大量内置函数可以操作数组。
<?php
$nums = [3, 1, 2];
$nums[] = 5; // append
sort($nums);
echo implode(", ", $nums), "\n"; // 1, 2, 3, 5
$ages = ["ann" => 31, "bob" => 25];
$ages["cy"] = 40;
foreach ($ages as $person => $age) {
echo "$person is $age\n";
}
echo $ages["zed"] ?? 0, "\n"; // 0 (null coalescing)
$evens = array_filter($nums, fn($n) => $n % 2 === 0);
$squares = array_map(fn($n) => $n * $n, $nums);
echo json_encode(array_values($evens)), " ", json_encode($squares), "\n"; // [2] [1,4,9,25]
echo count($ages), " ", array_key_exists("bob", $ages) ? "yes" : "no", "\n"; // 3 yes数组在赋值时会被复制(写时复制),这与按句柄传递的对象不同。
类、构造器属性提升与枚举
<?php
declare(strict_types=1);
enum Role: string
{
case Admin = "admin";
case Viewer = "viewer";
}
final class User
{
public function __construct(
public readonly string $name,
public readonly Role $role = Role::Viewer,
) {}
public function label(): string
{
return "{$this->name} ({$this->role->value})";
}
}
$u = new User("Ann", Role::Admin);
echo $u->label(), "\n"; // Ann (admin)
echo Role::from("viewer")->name, "\n"; // Viewer构造器属性提升(PHP 8.0)可以在构造函数签名中同时声明并赋值属性。readonly 属性(8.1)只能设置一次,带值枚举(8.1)可以把枚举项映射到字符串或整数。同样可以使用接口、抽象类和 trait。
错误处理
现代 PHP 对大多数错误都会抛出异常。对于可预期的失败,捕获 Exception 的子类;Throwable 还涵盖 TypeError 等引擎错误。
<?php
function parseAge(string $text): int
{
if (!ctype_digit($text)) {
throw new InvalidArgumentException("invalid age: $text");
}
return (int) $text;
}
try {
echo parseAge("41"), "\n"; // 41
echo parseAge("abc"), "\n";
} catch (InvalidArgumentException $e) {
echo $e->getMessage(), "\n"; // invalid age: abc
} finally {
echo "done\n";
}一个完整的小程序:JSON API 接口
把它保存为 api.php,运行 php -S localhost:8000,然后打开 http://localhost:8000/api.php?name=Ann。它会读取查询参数、校验后返回 JSON。
<?php
declare(strict_types=1);
header("Content-Type: application/json; charset=utf-8");
$name = trim($_GET["name"] ?? "");
if ($name === "" || mb_strlen($name) > 50) {
http_response_code(400);
echo json_encode(["error" => "name must be 1 to 50 characters"]);
exit;
}
$response = [
"message" => "Hello, $name!",
"length" => mb_strlen($name),
"time" => date(DATE_ATOM),
];
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);$_GET、$_POST 和 $_COOKIE 保存请求数据。请把其中的每个值都当作不可信的。
新手常见错误
- 使用会转换类型的
==比较;请使用===和!==。 - 忘记变量名前的
$,或语句末尾的分号。 - 用
md5或sha1存储密码。请使用password_hash和password_verify。 - 对 UTF-8 文本使用
strlen,它统计的是字节数。统计字符数请用mb_strlen。 - 运行过时的 PHP 版本。请使用仍受支持的 PHP 8 版本,以获得安全修复和现代特性。
接下来学什么
php.net 上的官方 PHP 手册记录了每一个函数,还有语言参考和用户笔记。学习包管理器 Composer 和 PSR 编码规范,然后尝试框架:开发应用用 Laravel 或 Symfony,开发小型 API 用 Slim。PHPUnit 是标准的测试工具。
常见问题
PHP 现在还值得学吗?
值得。它驱动着大部分网络,包括 WordPress 网站,而搭配 Laravel 或 Symfony 的现代 PHP 8 是开发 Web 应用的高效方式。维护和开发 PHP 系统的工作岗位很常见。
PHP 是前端语言还是后端语言?
后端。PHP 在服务器上运行,把生成好的 HTML、JSON 或文件发送给浏览器,浏览器永远看不到 PHP 代码。
echo 和 print 有什么区别?
两者都用于输出文本。echo 可以接收多个用逗号分隔的参数,没有返回值;print 只接收一个参数,返回 1。实际上大多数代码使用 echo。
declare(strict_types=1) 有什么作用?
它让该文件中发起的函数调用对标量类型声明采用严格模式,所以把字符串 "5" 传给 int 参数时,会抛出 TypeError 而不是被自动转换。