本文是笔者在对PHP进行了解性的学习时所记录的笔记,在撰写过程中大量使用了AI,但也并非完全地将AI的输出进行简单的复制粘贴。
由于此前笔者有过C++的学习经历,故本文会较为注重PHP与C++不同的地方,而两者相似之处通常一笔带过,不作赘述。
由于笔者水平有限,难免会有错漏。
若有纰漏,欢迎读者的批评与指正!
变量
变量以$
符号开头,后面跟变量名
命名规则与C++类似
$name="Alice"; //字符串
$age = 25; //整数
$is_student = true; //布尔值
数据类型
PHP主要的数据类型如下
- 整数
- 浮点数
- 布尔值
- 字符串
- 数组
- 对象
- NULL
PHP是动态类型语言(弱类型语言),不需要显式声明变量类型
数据类型的转换
数字和字符串可以相互自动进行类型转换
对于布尔值,非0数字和非空字符串会被转换为true,其余转换为false
布尔值转换为字符串会先转换成整型1或0
也可以用显示的强制转换,如(int)$var
或者使用函数
intval();//参数传入要转换的值,返回转换后的结果
floatval();
strval();
boolval();
php中数组和对象可以相互转化,
转换后数组的键会变成对象的属性,数组的值会变成属性的值,如果键是整数,则这个键会变成字符串
使用 $obj = (object)$array;
来转换
如果数组中有嵌套的数组,也会一并被转换成对象
对象也可以用(array)
转换成数组,但只能把public的属性转换出来,而且不能嵌套转换对象的属性对象
运算符
php与C++运算符不同之处在于
php有===与!==严格比较运算符,要求比较的两者值相等(或可以转换)并且类型也相同
php使用.
来拼接字符串,也可以用.=
来拼接
php支持短路运算符??
,又叫做null合并运算符
$value = $a ?? 'default'; //如果$a为null 则返回后面的值'default'
其作用是将null值去除
php的字符串支持++,但只有空字符串支持–
其作用是将字符串最后一个字符进行++(ASCII意义上的)
对于空字符串,支持++和–,则会先转换成数字0,再+1或-1
数组
PHP的数组可以同时包含多种类型的元素
PHP有两种数组,一种是索引数组,一种是关联数组(键值对数组,类似c++的map,python的dict)
索引数组的定义
$clolrs = array("red","green","blue"); // 索引数组使用array()函数定义
$fruits = ["apple","banana","cherry"]; // 索引数组使用短数组语法 与Python类似
$Array = []; // 空数组
元素访问
echo $fruits[0]; // 输出 apple
关联数组的定义
php的关联数组的key只能是整型或字符串,如果使用了布尔值、浮点数,也会分别被自动转为整型和字符串
类似地,关联数组也可以用短数组语法
$person = array("name"=>"Alice","age"=>25); //关联数组 array()
$person = ["name"=>"Alice","age"=>25]; //关联数组 短数组语法
多维数组的定义与访问
$student = [
["name"=>"Alice","age"=>20],
["name"=>"Bob","age"=>22],
["name"=>"Charlie","age"=>21]
]; //甚至可以将两种数组混用
echo $student[0][age]; //输出 20
一种插入元素的方法
$arr[] = 5; //往数组末尾插入5
非连续的索引
php的数组允许非连续的索引,并且count的结果仍为实际上数组元素的个数
操作数组的内置函数 这些函数不是成员函数
$arr = [1,2,3]; //已经声明并初始化了一个数组$arr
echo count($arr); //计数:输出 3
unset(arr[2]); //删除索引为2的元素
字符串
单引号字面量定义的字符串
echo 'Hello, $name'; //原样输出Hello, $name
变量不被解析,只有\\和\'这两个转义字符有效
双引号字面量定义的字符串
变量会被解析,转义字符会生效
字符串与布尔值
字符串可以被隐式转换为布尔值
空字符串为false 非空字符串为true
$str1=""; //false
$str2=" "; //true
$str3=" "; //true
$str4="hahaha"; //true
字符串拼接
使用.符号拼接,与C++中使用+不同
$greet_words="Hello, ".$name; //将字符串"Hello, "和变量$name存储的字符串拼接
类似地,也可以使用.=
来拼接字符串
$name="Charry";
$name.="Brown"; //$name变为"CharryBrown"
控制与循环语句
if与C++一致
if (条件1) {
// 当条件1为真时执行的代码
} else if (条件2) {
// 当条件1为假且条件2为真时执行的代码
} else {
// 当条件1和条件2都为假时执行的代码
}
while()与C++一致 值得注意的是,php的整型可以被隐式转换成布尔值,因此可以使用类似while($n--)
的语法
while($n--)
{
echo $n;
}
switch与C++一致
switch(变量)
{
case 值1:
break;
case 值2:
break;
default:
//...
}
php的for不能像C++一样使用for(…in…)语法
类似地,可以使用foreach
foreach($array as $value)
{
//$value将会遍历赋值$array中的对象
}
还可以同时遍历键和值
foreach($array as $key => $value)
{
//$key... $value...
}
函数
php没有主函数,函数和顶级流程代码都写作顶级语句
函数使用function定义,将C++中原本返回值类型的地方换成了function
function greet($name) //定义
{
return "Hello,".$name;
}
echo greet("Alice"); //调用
实际上,自php7开始,也支持指定返回值类型和参数类型,但具体的写法仍与C++不同
function add(int $a,int $b):int
{
return $a+$b;
}
php的函数签名包括函数名
,参数列表
,返回值类型
简单地说,就是包括了函数声明语句
如这句话:function add(int $a, int $b): int
就囊括了函数签名的全部内容
如果返回值类型、参数类型没有指定,就不会被包括
php的函数不支持重载,即使函数签名不同,这点与C++不同
函数也支持默认值,其规则与C++类似,有默认值的参数要在没默认值的参数前
function greet(int $times,string $name = "Guest"): string {
while($times--)
{
echo "Hello, $name!"."<br>";
}
}
超全局变量
PHP中有一种超全局变量,可以在脚本的任何位置访问,不需要global关键字
有一些超全局变量与http请求有关
$_GET
$_GET用于收集通过URL查询字符串传递的变量,适用于HTTP GET方法
//假如下面的代码写在了index.php
//并且通过了这个URL访问这个php:index.php?name=Alice&age=25
$name=$_GET['name'];
$age=$_GET['age'];
http get方法传递的参数已经被存储在一个叫$_GET的关联数组
其键和值都是字符串 即使传递前不是字符串,但是经过了这样的方式传递,在传递前会被自动转换为字符串
可能需要配合parseInt()等函数来使用
parseInt()
httpspecialchars(<要转换的字符串>) //这个函数可以将特殊字符转换为html实体,防止html注入
所谓将特殊字符转换为html实体的意思是:
本来< >等字符在html中是有特殊效果的,想要显示原本的字符,需要用<等HTML字符实体
为了避免有人通过输入的字符串来干扰你的网页,你需要事先用这样的方法把这些字符变成字符实体
这样这些字符就不会起到其在html中的特殊效果
$_POST
类似地,通过POST方法传递的参数也被存储在了一个叫_POST的关联数组
$name = $_POST['name']; //获取POST请求中的name参数
$_COOKIE
访问客户端发送的cookie内容,与前者类似
$_REQUEST
这个可以同时访问$_GET
,$_POST
,$_COOKIE
的变量,相当于是一个整合了三者内容的关联数组
$_FILES
可以访问通过HTTP POST方法上传的文件
//一个简单的示例
$fileName = $_FILES['file']['name']; //获取上传文件的名称
类与对象
php中有类似C++中的类
类的定义与C++相似,但又有一定的不同
abstract class Animal
{
//属性的声明 属性的权限写在前面
protected $name; //public protected privete等权限与C++中一致
protected $age; //但是写法不同
//构造函数 定义方法与C++中不同
public function __construct($name)
{
$this->name = $name; //在类成员函数使用成员属性 也必须使用-> 这点与C++不太一样
}
//成员函数 权限写在前面
public function getInfo()
{
return "Name: ".$this->name.", Age: ".$this->age;
}
//纯抽象(纯虚)方法 在子类中必须要将其重载
abstract public function makeSound();
}
一个子类Dog
class Dog extends Animal
{
private $breed; //私有属性
//构造函数的重载
public function __construct($name,$age,$breed)
{
parent::__construct($name,$age); //调用父类的构造函数
$this->breed = $breed;
}
//重载了父类的纯抽象方法
public function makeSound()
{
return "Woof! Woof!";
}
public function getBreed()
{
return $this->breed; //自己独有的方法 获取Breed狗的品种信息
}
public function getInfo()
{
return parrent::getInfo().", Breed: ".this->$breed; //重载了父类的方法
}
}
创建对象和使用
$dog = new Dog("Wong",3,"Black"); //Dog类变量引用Dog类对象
echo $dog->makeSound();
- abstract的类是抽象类,不能被实现
- abstract与C++中的virtual并不相同,abstract标记的方法是抽象方法,也就是C++中的纯抽象函数,必须不能有具体实现,在非抽象子类中必须实现
- 只有abstract的类,才能有abstract的方法
- 实例化的子类对象,如果普通的方法没有重载,则调用父类的方法(与C++一致)
- 由于PHP中不能指定变量类型,所以不像C++中有父类变量引用(或者父类指针指向)子类对象这种用法,也不会有因此产生的一些特性
- PHP不支持多重继承
//方式一
class Animal{
public function makeSound() {
return "Some sound";
}
}
class Dog extends Animal{
public function makeSound()
{
return "Woof!";
}
}
//方式二
abstract class Animal{
abstract public function makeSound() {
return "Some sound";
}
}
class Dog extends Animal{
public function makeSound()
{
return "Woof!";
}
}
接口
php不支持多重继承,采用接口的方式来实现类似的效果
<?php
interface Animal{
public function makeSound(); //interface 接口的方法必须不能有实现 并且属性一定是public
}
interface Pet{
public function play();
}
class Dog implements Animal,Pet{ //使用implements(v.实现)关键字来表明该类要实现这两个接口
public function makeSound()
{
return "Woof!"; //在接口的子类中 必须实现方法
}
public function play()
{
return "Playing fetch!";
}
}
$dog = new Dog();
echo $dog->makeSound()."<br>"; //html网页环境 使用<br>换行
echo $dog->play();
?>
接口与抽象类类似,但不同之处在于
- 一个class可以implements多个接口,而一个class不能extends多个抽象类
- 接口中的每一个方法都不能有实现(方法一定没有函数体),而抽象类可以
- 接口中的每一个方法属性必须是public,而抽象类可以是其他的属性
接口还可以有子接口,继承父接口
子接口继承父接口,可以继承多个父接口,这与类的不能多重继承不同
若要实现子接口,必须要实现子接口和父接口的所有方法
特征trait
使用关键字trait可以定义特征trait
trait CanFly
{
private function deepfly()
{
echo "Flying!";
}
public function fly()
{
$this->deepfly();
}
}
trait CanSwim
{
public function swim()
{
echo "Swimming!";
}
}
class Bird
{
use CanFly,CanSwim;
}
$bird = new Bird();
$bird->fly();
使用use关键字在类中引入trait,相当于在类中复用了trait中声明的方法
trait可以使用extends关键字继承其他的trait
trait中的方法可以被将其引入的class和将其继承的trait重写,但属性不能改变
前置声明后置实现
php不支持前向声明,函数、类等被使用之前必须先实现
而且也不能只写声明不写实现,除非是abstrat函数
引入其他php
require和include可以用于引入其他的php文件
如果被引入的php文件中有return语句
则require或include将会返回该文件return语句返回的对象/变量
当文件被引入时,其中的函数、类、变量等都会被引入到当前文件的全局作用域
require与include的主要区别在于对错误的处理不同
require引入文件出错,会产生致命错误,使得脚本停止执行
include引入文件出错,会产生警告,但脚本继续执行
$config = include "config.php";
$server_config = require "server_config.php"
如果没有返回值,也可以不用变量 c o n f i g , config, config,server_config来接收
php与MySQL
使用拓展MySQLi,可以在php中对MySQL数据库进行操作
连接数据库
$mysqli = new mysqli("地址","用户名","密码","要操作的数据库","端口(也可以省略)");
如果连接失败
$mysqli -> connect_error //值为真
查询
使用数据库对象的成员方法query来查询,传入查询语句作为参数
返回查询结果对象
$result = $mysqli->query("SELECT * FROM users");
结果对象可以使用成员方法fetch_assoc()
,这个方法每使用一次,都会返回查询结果的下一行,如果全部行都返回过了,就返回null,这个特性使得它可以与while语句搭配使用
每一行通常都是一个关联数组,以表头为键
while($row = $result->fetch_assoc())
{
print_r($row);
}
预处理语句
预处理语句是把一条SQL语句中的参数分离出来,但是又和字符串拼接不同,可以避免SQL注入
使用有三个步骤
- 使用
prepare()
准备一个SQL语句,把要替换的参数替换为?
- 使用
bind_param()
将参数绑定到SQL语句中 - 使用
execute()
执行SQL语句
$stmt = $mysqli->prepare("SELECT * FROM users WHERE id = ?");
$id = 1;
$stmt->bind_param("i",$id);//i表示整型 后面是实际的参数
$stmt->execute(); //执行语句
$result = $stmt->get_result(); //获取结果
$stmt->close(); //关闭查询语句
在bind_param()中,常用的类型字符包括:
i
:表示整数(integer)d
:表示双精度浮点数(double)s
:表示字符串(string)b
:表示二进制数据(blob)
如果有多个参数,直接拼起来,例如:
$stmt->bind_param("ss", $name, $email);
插入数据
$stmt = $mysqli->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param("ss", $name, $email);
$name = 'John';
$email = 'john@example.com';
$stmt->execute();
更新数据
$stmt = $mysqli->prepare("UPDATE users SET email = ? WHERE id = ?");
$stmt->bind_param("si", $email, $id);
$email = 'newemail@example.com';
$id = 1;
$stmt->execute();
删除数据
$stmt = $mysqli->prepare("DELETE FROM users WHERE id = ?");
$stmt->bind_param("i", $id);
$id = 1;
$stmt->execute();
事务
事务是一组sql语句,其特点是执行要么全部成功,要么全部失败
$mysqli->begin_transaction(); //开始事务 此后该数据库对象执行的语句都被视作事务中的语句
try {
// 执行第一条 SQL 语句
$sql1 = "INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')";
$mysqli->query($sql1);
// 执行第二条 SQL 语句 也可以使用预处理语句
$stmt = $mysqli->prepare("INSERT INTO orders (user_id ,product_id) VALUES (LAST_INSERT_ID(),?)");
$product_id = 1;
$stmt->bind_param("i",$product_id);
$stmt->execute();
// 提交事务
$mysqli->commit();
echo "Transaction completed successfully.";
} catch (Exception $e) { //如果发生错误,则可以用数据库对象的rollback()回滚事务
// 回滚事务
$mysqli->rollback();
echo "Transaction failed: " . $e->getMessage();
}