从零开始学 PHP 系列(二):PHP 基础语法与数据类型深入

摘要:在上一篇文章中,我们搭建了开发环境并运行了第一个 PHP 程序,初步感受了它的魅力。从本篇开始,我们将正式踏入 PHP 语法的大门。你是否曾被编程中的"变量""常量""数据类型"这些术语搞得一头雾水?别担心,本文将用最生活化的比喻,带你系统地掌握 PHP 的基础语法规则、八种数据类型及其转换方式、运算符的使用,以及字符串处理的常用技巧。学完本篇,你将能独立编写具有数据处理和逻辑判断能力的小脚本,为后续的流程控制和函数学习打下坚实基础。让我们开始这场充满代码与趣味的探索吧。


一、引言:编程语言的"词汇"与"语法"

就像学英语要先学单词和语法一样,学任何编程语言,首先要掌握它的"词汇"(数据类型、变量、常量)和"语法"(如何组织这些词汇,如表达式、运算符)。PHP 的语法非常宽容,对初学者友好,但这并不意味着可以随意书写。养成良好的编码习惯,从理解底层概念开始。

本篇的内容架构是:变量与常量 → 八种数据类型详解 → 类型转换与判断 → 运算符 → 字符串函数入门


二、变量:存储数据的"盒子"

2.1 什么是变量?

想象你有一个贴了标签的空盒子,你可以把任何东西放进去------一个数字、一段文字、一串名单。这个盒子就是变量。在 PHP 中,变量名就是标签,变量值就是盒子里的东西,而且盒子里的东西随时可以更换。

2.2 变量的声明与命名规则

PHP 变量必须以 $ 符号开头,后面紧跟变量名。变量名区分大小写,只能包含字母、数字、下划线,且不能以数字开头。通常我们使用驼峰式或下划线式命名。

php 复制代码
<?php
// 合法命名
$name = "张三";
$_age = 25;
$myFavoriteColor = "蓝色";   // 驼峰式
$user_first_name = "李";    // 下划线式
​
// 非法命名(不要这样写)
// $123abc = "error";       // 不能以数字开头
// $my-var = "error";       // 不能包含连字符
?>

2.3 变量的赋值与传值方式

PHP 中有两种赋值方式:传值赋值 (默认)和引用赋值

传值赋值:将原变量的值复制一份给新变量,两者互不影响。

php 复制代码
<?php
$a = 10;
$b = $a;      // $b 得到 $a 的副本
$b = 20;
echo $a;      // 输出 10,$a 不受 $b 的影响
?>

引用赋值 :在变量前加 &,使新变量指向原变量的"内存地址",一改俱改。

php 复制代码
<?php
$a = 10;
$b = &$a;     // $b 是 $a 的别名,指向同一内存地址
$b = 20;
echo $a;      // 输出 20,因为 $a 和 $b 本质上是同一个值
?>

2.4 变量的变量

PHP 允许使用一个变量的值作为另一个变量的名称,称为"变量的变量"。

php 复制代码
<?php
$fruit = "apple";
$$fruit = "红富士";  // 相当于 $apple = "红富士";
echo $apple;        // 输出 "红富士"
?>

虽然灵活,但可读性差,实际开发中极少使用。


三、常量:不变的"固定标签"

3.1 什么是常量?

常量与变量相对,一旦定义,其值在整个脚本运行期间不可更改。用于存储不会变的值,如网站域名、数据库连接参数、数学常数等。

3.2 定义常量的两种方式

方式一:define() 函数(传统方式,运行阶段定义)

php 复制代码
<?php
define("SITE_NAME", "我的博客");
define("MAX_LOGIN_ATTEMPTS", 5);
define("PI", 3.14159);
​
echo SITE_NAME;    // 输出 "我的博客",常量名前不需要 $
echo PI;           // 输出 3.14159
?>

方式二:const 关键字(编译阶段定义,性能略好,用于类常量更佳)

php 复制代码
<?php
const DB_HOST = "localhost";
const DB_USER = "root";
​
echo DB_HOST;   // 输出 "localhost"
?>

3.3 常量的特点与魔术常量

  • 常量名通常全大写,用下划线分隔(约定俗成)。

  • 常量是全局的,无需关心作用域。

  • define 可以定义表达式(PHP 7+),const 不能用于条件语句中。

魔术常量:PHP 预定义的一些常量,值会随着所在位置变化。

php 复制代码
<?php
echo __LINE__;     // 当前行号
echo __FILE__;     // 当前文件完整路径
echo __DIR__;      // 当前文件所在目录
echo __FUNCTION__; // 当前函数名(在函数内)
?>

四、PHP 的八种数据类型深度剖析

数据类型定义了变量可以存储什么种类的数据,以及能对这些数据做什么操作。PHP 是弱类型语言,同一个变量可以先后存储不同类型的值,但理解每种类型至关重要。

4.1 整型(Integer)

用于存储没有小数点的数字,可以是十进制、八进制(0 开头)、十六进制(0x 开头)、二进制(0b 开头,PHP 5.4+)。

php 复制代码
<?php
$decimal = 42;         // 十进制
$octal = 0755;         // 八进制(以 0 开头,等于十进制的 493)
$hex = 0xFF;           // 十六进制(等于十进制的 255)
$binary = 0b1100;      // 二进制(等于十进制的 12)
​
echo $decimal;         // 42
echo PHP_INT_MAX;      // 本平台最大整数,通常是 9223372036854775807(64 位系统)
echo PHP_INT_MIN;      // 最小整数
?>

溢出处理:如果给定的数超出整型范围,PHP 会将其自动解释为浮点型。

4.2 浮点型(Float / Double)

用于存储带小数点的数字或极大/极小的数(科学计数法)。

php 复制代码
<?php
$price = 19.99;
$distance = 3.4e3;     // 3.4 × 10³ = 3400
$tiny = 7E-10;         // 7 × 10⁻¹⁰
​
var_dump($price);      // float(19.99)
?>

精度问题警示:浮点数在计算机内部是二进制近似存储,运算可能产生微小的误差。

php 复制代码
<?php
$a = 0.1;
$b = 0.2;
$c = $a + $b;
var_dump($c == 0.3);   // 输出 bool(false)!
// 实际 $c 可能是 0.30000000000000004
// 比较浮点数应使用一个误差范围,如 abs($c - 0.3) < 0.00001
?>

4.3 布尔型(Boolean)

只有两个值:truefalse,不区分大小写(TRUE/False 皆可,但推荐小写)。常用于条件判断。

php 复制代码
<?php
$is_logged_in = true;
$has_permission = false;
​
if ($is_logged_in) {
    echo "欢迎回来!";
}
?>

哪些值被视为 false(强制转换时)?

  • 布尔值 false 本身

  • 整型 0

  • 浮点型 0.0

  • 空字符串 "" 和字符串 "0"

  • 空数组 []array()

  • NULL

  • 从零值变量创建的 SimpleXML 对象

其余一切值都被视为 true。这叫做"松散比较"。

4.4 字符串(String)

字符串是字符的序列。PHP 中有四种定义方式。

① 单引号字符串 单引号内的字符几乎都被当作字面值,只有两个转义字符有效:\\(单引号)和 \\'(反斜杠本身)。变量不会被解析。

php 复制代码
<?php
$name = "小明";
echo '你好,$name';   // 输出:你好,$name(变量未被解析)
echo 'I\'m happy';   // 输出:I'm happy
?>

② 双引号字符串 双引号会解析其中的变量和转义字符(\n, \r, \t, \\, \$ 等)。

php 复制代码
<?php
$count = 5;
echo "你有 $count 条新消息。";   // 输出:你有 5 条新消息。
echo "第一行\n第二行";           // 在命令行会换行,HTML 中需要用 <br> 或查看源代码
?>

如果变量名后紧跟字母数字,可用花括号明确变量边界:

php 复制代码
<?php
$fruit = "apple";
echo "I like {$fruit}s.";   // 输出:I like apples.
?>

③ Heredoc 语法(<<< 适合定义包含大量文本、保留换行的字符串。语法类似双引号,会解析变量。

php 复制代码
<?php
$title = "公告";
$str = <<<EOT
<h2>$title</h2>
<p>这是多行文本内容,
   支持变量解析和双引号无需转义。</p>
EOT;
echo $str;
?>

标识符 EOT(可以任意命名)所在行必须仅包含自身,不可有空格或其他字符。

④ Nowdoc 语法(<<<'EOT' 类似单引号,不解析变量。

php 复制代码
<?php
$str = <<<'EOT'
这里不会解析 $变量,相当于加强版单引号。
EOT;
?>

4.5 数组(Array)

数组可以存储多个值,是 PHP 中最强大、最常用的数据结构之一(下一篇会专门深入数组)。这里先认识创建和访问。

索引数组(键为数字):

php 复制代码
<?php
$colors = array("红", "绿", "蓝");
// PHP 5.4+ 简写
$colors = ["红", "绿", "蓝"];
echo $colors[0];   // 输出 "红"
$colors[] = "黄";  // 自动追加到末尾,索引 3
?>

关联数组(键为字符串):

php 复制代码
<?php
$user = [
    "name" => "李四",
    "age"  => 30,
    "city" => "上海"
];
echo $user["name"];  // 输出 "李四"
?>

4.6 对象(Object)

对象是面向对象编程的核心,通过 new 关键字实例化一个类得到。

php 复制代码
<?php
class Person {
    public $name;
    public function sayHello() {
        echo "你好,我叫 $this->name";
    }
}
​
$p = new Person();
$p->name = "王五";
$p->sayHello();   // 输出:你好,我叫王五
?>

4.7 NULL 类型

NULL 表示变量没有值。以下情况变量会被视为 NULL:

  • 被显式赋值为 NULL

  • 尚未被赋值。

  • 使用 unset() 销毁后的变量。

php 复制代码
<?php
$var = NULL;
var_dump($var);         // NULL
$var2;                  // 未赋值,值为 NULL(但会触发 Notice 警告)
unset($var);
var_dump($var);         // NULL(且变量 $var 已不存在)
?>

4.8 资源(Resource)

资源是一种特殊的变量,保存到外部资源(如文件、数据库连接、图像画布)的引用。PHP 负责管理这些资源,用完通常需手动释放或等脚本结束自动回收。

php 复制代码
<?php
$file = fopen("test.txt", "r");   // 打开文件,返回资源
var_dump($file);                  // resource(...)
fclose($file);                    // 关闭文件,释放资源
?>

资源在调试时看不到具体数据,只能看到类型编号。


五、类型判断、获取与转换

5.1 获取数据类型

var_dump() 用于调试,输出变量类型和值。gettype() 返回类型的字符串名称。

php 复制代码
<?php
$data = 123;
var_dump($data);      // int(123)
echo gettype($data);  // "integer"
?>

5.2 类型判断函数

PHP 提供了一系列以 is_ 开头的函数判断类型:

php 复制代码
<?php
$val = "hello";
is_string($val);    // true
is_int($val);       // false
is_float($val);     // false
is_bool($val);      // false
is_array($val);     // false
is_null($val);      // false
is_numeric("123");  // true(判断是否为数值或数值字符串)
isset($val);        // true(变量存在且不为 NULL)
empty($val);        // false(变量为空时返回 true)
?>

isset()empty() 的区别是常见面试题:

  • isset():变量已设置且值不为 NULL

  • empty():值等于空(空字符串、0、"0"、false、NULL、空数组等)返回 true,即使变量不存在也不产生警告。

5.3 类型转换

自动类型转换(类型转换):PHP 会根据上下文自动转换类型。

php 复制代码
<?php
$num = "10" + 5;      // 字符串 "10" 转为整数 10,结果 15
$str = "10hello" + 5; // 字符串 "10hello" 转为整数 10,结果 15(产生 Warning)
$concat = "10" . 5;   // 点运算符强制将 5 转为字符串,结果 "105"
?>

强制类型转换:在变量前加括号指定目标类型,不会改变原变量。

php 复制代码
<?php
$x = 3.14;
$y = (int)$x;   // $y = 3,$x 仍是 3.14
$z = (string)$x; // $z = "3.14"
?>

常用强制转换关键字:(int), (float), (string), (bool), (array), (object)

函数转换intval(), floatval(), strval()

php 复制代码
<?php
$a = "42px";
echo intval($a);   // 42
?>

六、运算符:让数据"动"起来

运算符是处理数据的工具。PHP 的运算符与大部分语言类似。

6.1 算术运算符

运算符 名称 示例
+ $a + $b
- $a - $b
* $a * $b
/ $a / $b
% 取模 $a % $b
** 乘方 $a ** $b(PHP 5.6+)
php 复制代码
<?php
echo 10 % 3;   // 输出 1
echo 2 ** 3;   // 输出 8
?>

6.2 赋值运算符

= 是基本赋值,可与算术运算符组合:

php 复制代码
<?php
$a = 10;
$a += 5;   // 相当于 $a = $a + 5;
$a .= "元"; // 相当于 $a = $a . "元";(连接字符串)
?>

6.3 比较运算符

比较表达式返回布尔值。

运算符 名称 示例
== 等于 $a == $b
=== 全等 $a === $b
!= 不等 $a != $b
!== 不全等 $a !== $b
< 小于 $a < $b
> 大于 $a > $b
<= 小于等于 $a <= $b
>= 大于等于 $a >= $b
<=> 太空船 $a <=> $b

== vs === 是核心区别:

  • == 会进行类型转换后再比较。

  • === 要求类型和值都相等。

php 复制代码
<?php
var_dump(0 == "0");    // true,因为字符串 "0" 转为整数 0
var_dump(0 === "0");   // false,类型不同(整数 vs 字符串)
var_dump(0 == false);  // true,false 转为整数 0
var_dump(0 === false); // false

// 太空船运算符:$a <=> $b 当 $a 小于/等于/大于 $b 时,分别返回 -1/0/1
echo 5 <=> 10;   // -1
echo 10 <=> 10;  // 0
echo 15 <=> 10;  // 1
?>

6.4 逻辑运算符

用于组合多个条件。

运算符 名称 示例
&& / and $a && $b
|| / or $a || $b
! !$a
xor 异或 $a xor $b

&&and 优先级高,||or 高,这是常见的坑。推荐统一使用 &&||

php 复制代码
<?php
$logged = true;
$admin = false;

if ($logged && $admin) {
    echo "进入管理面板";
} else {
    echo "权限不足";
}

// 短路特性:如果左侧已能决定结果,右侧不再执行
$result = false && someFunction();  // someFunction() 不会被执行
?>

6.5 字符串运算符

. 用于连接字符串,.= 用于连接并赋值。

php 复制代码
<?php
$hello = "你好";
$world = "世界";
echo $hello . ", " . $world . "!";  // 输出:你好, 世界!

$msg = "Hello";
$msg .= " PHP";  // $msg = "Hello PHP"
?>

6.6 递增/递减运算符

++(递增 1),--(递减 1),有前置后置之分,影响表达式的返回值。

php 复制代码
<?php
$a = 5;
echo $a++;   // 输出 5,然后 $a 变为 6(后置递增:先返回旧值,再自增)
echo ++$a;   // $a 先变为 7,然后输出 7(前置递增:先自增,再返回新值)
?>

6.7 三元运算符与空合并运算符

三元运算符条件 ? 值1 : 值2

php 复制代码
<?php
$age = 20;
$status = ($age >= 18) ? "成年人" : "未成年人";
echo $status;  // 输出:成年人
?>

空合并运算符 (PHP 7+):??,用于简化 isset() 的三元判断。

php 复制代码
<?php
$name = $_GET['user'] ?? "游客"; // 若 $_GET['user'] 存在且不为 NULL,用其值;否则用 "游客"
?>

空合并赋值运算符 (PHP 7.4+):??=

php 复制代码
<?php
$count = null;
$count ??= 10;  // 等价于 $count = $count ?? 10;
echo $count;    // 10
?>

七、字符串函数入门:玩转文字

字符串处理是 Web 开发的高频操作。PHP 内置了上百个字符串函数,这里列举最常用的一部分。

7.1 获取字符串长度:strlen()

php 复制代码
<?php
echo strlen("hello");      // 5
echo strlen("你好");        // 6(UTF-8 编码下,一个汉字占 3 个字节)
echo mb_strlen("你好");     // 2(mb_* 系列函数支持多字节字符,更准确)
?>

7.2 查找与替换

php 复制代码
<?php
$text = "Hello World, Hello PHP";

// strpos():查找字符串首次出现的位置(区分大小写,未找到返回 false)
$pos = strpos($text, "World");
var_dump($pos);   // int(6)(从 0 开始计数)

// str_replace():替换字符串
$new = str_replace("Hello", "你好", $text);
echo $new;        // 你好 World, 你好 PHP

// str_ireplace():不区分大小写的替换
?>

注意strpos 可能返回 0(第一个字符),而 0 在松散比较中等同于 false,因此判断时必须用 === false

php 复制代码
<?php
if (strpos($text, "Hello") !== false) {
    echo "找到了";
}
?>

7.3 截取与分割

php 复制代码
<?php
$str = "abcdefg";

// substr():截取子串(参数:字符串, 起始位置, 长度)
echo substr($str, 0, 3);    // "abc"
echo substr($str, -3);      // "efg"(负数从末尾开始)
echo substr($str, 3);       // "defg"(省略长度,取到末尾)

// explode():按分隔符分割字符串为数组
$list = "苹果,香蕉,橘子";
$arr = explode(",", $list);
var_dump($arr);   // ["苹果", "香蕉", "橘子"]

// implode() / join():将数组合并为字符串
echo implode(" | ", $arr);  // "苹果 | 香蕉 | 橘子"
?>

7.4 大小写转换与格式化

php 复制代码
<?php
echo strtolower("HELLO");   // "hello"
echo strtoupper("hello");   // "HELLO"
echo ucfirst("hello");      // "Hello"(首字母大写)
echo ucwords("hello world");// "Hello World"(每个单词首字母大写)

// trim():去除首尾空白字符(换行、空格、制表符)
$input = "  有空格的用户名  ";
echo trim($input);          // "有空格的用户名"

// str_pad():填充字符串到指定长度
echo str_pad("42", 5, "0", STR_PAD_LEFT);  // "00042"
?>

7.5 HTML 相关函数

php 复制代码
<?php
// htmlspecialchars():将特殊字符转为 HTML 实体,防止 XSS
$user_input = '<script>alert("XSS")</script>';
echo htmlspecialchars($user_input);
// 浏览器将显示为文本而非执行脚本

// strip_tags():去除所有 HTML 和 PHP 标签
echo strip_tags("<p>这是<b>粗体</b></p>");  // "这是粗体"
?>

7.6 字符串与数组互转的趣味应用

php 复制代码
<?php
// str_split():将字符串按字符分割成数组
$chars = str_split("hello");
print_r($chars);  // ['h', 'e', 'l', 'l', 'o']

// str_word_count():返回单词数量或单词数组
echo str_word_count("Hello PHP world");  // 3
?>

八、综合示例:一个简单的用户信息卡片

我们将本篇的知识整合起来,编写一个动态生成用户信息卡片的小脚本。

php 复制代码
<?php
// 模拟用户数据
$username = "  张三  ";
$age = 28;
$city = "北京";
$hobbies = ["编程", "摄影", "旅行"];
$bio = "热爱技术,喜欢用代码创造价值。";

// 数据清洗
$username = trim($username);
$safe_bio = htmlspecialchars($bio);
$user_status = ($age >= 18) ? "成年人" : "未成年人";
$hobby_text = implode("、", $hobbies);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title><?php echo $username; ?> 的个人卡片</title>
    <style>
        .card { border: 1px solid #ccc; padding: 20px; width: 300px; }
        .avatar {
            width: 100px;
            height: 100px;
            border-radius: 50%;
            background: #4299e1;
            color: white;
            font-size: 40px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .tag { background: #eee; padding: 2px 8px; margin: 2px; display: inline-block; }
    </style>
</head>
<body>
<div class="card">
    <!-- CSS绘制圆形头像,显示姓名第一个字,无网络请求 -->
    <div class="avatar">
        <?php echo mb_substr($username, 0, 1); ?>
    </div>
    <h2><?php echo $username; ?> <small>(<?php echo $user_status; ?>)</small></h2>
    <p>城市:<?php echo $city; ?></p>
    <p>爱好:<?php echo $hobby_text; ?></p>
    <p>简介:<?php echo $safe_bio; ?></p>
</div>
</body>
</html>

代码解析

  • 用本地 CSS 文字头像。

  • 使用变量存储用户信息。

  • trim() 清理用户名前后空格。

  • htmlspecialchars() 防止简介中可能存在的恶意代码。

  • 三元运算符判断用户是否成年。

  • implode() 将爱好数组拼接成字符串。

  • 在 HTML 中穿插 PHP 输出动态数据。

将上述代码保存为 card.php 并运行,即可看到一张用户信息卡片。

试着修改 $username 的值为 " 李四 <script>alert('!')</script>",观察 trimhtmlspecialchars 的作用。


九、总结

  • 变量 :以 $ 开头,是存储数据的容器;传值赋值与引用赋值的区别要牢记。

  • 常量 :使用 define()const 定义,值不可变,常用于配置项。

  • 八种数据类型:整型、浮点型、布尔型、字符串、数组、对象、NULL、资源。每种类型都有其适用场景和特性,浮点数精度问题、布尔值"假"的列表是常见考点。

  • 类型判断与转换var_dump() 是调试利器;is_* 系列函数用于判断;自动转换与强制转换需要留意规则,避免 bug。

  • 运算符 :算术、比较(== vs ===)、逻辑(短路特性)、字符串连接、递增递减、三元与空合并运算符,都是代码逻辑的基础。

  • 字符串函数strlenstrpossubstrexplodeimplodehtmlspecialchars 等是处理文本的瑞士军刀。


十、练习题(动手试试!)

  1. 定义两个变量 $a = 10; $b = "10";,分别用 ===== 比较它们,用 var_dump() 输出结果,解释为什么。

  2. 写一个脚本,接收一个名字参数 $_GET['name'],用空合并运算符设置默认值为"访客",然后输出"欢迎你,名字!"。注意使用 htmlspecialchars 防止 XSS。

  3. 给定字符串 "apple, banana, orange",用 explode 分割成数组,再用 foreach 循环打印每个水果(下一章才学循环,可提前搜索尝试或保留到下一篇)。

  4. 计算圆的面积(常量 PI = 3.14,半径 $r = 5),输出"半径为 5 的圆的面积是 78.5"。


如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享 ,也可以留言告诉我你遇到的其它问题,我会尽快回复。动手练习是掌握编程最快的方法,请务必亲手敲一遍本文的所有示例代码,并截图保存你的成果。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。