php学习

基础
# 打印
echo "Hello 1111!","Hello 2222"; // 可以输出多个字符串, 中间用,隔开
print "Hello 3333!"; // 只能输出一个字符串
echo("Hello 4444!"); // 也可以用括号括起来, 和上面效果相同
print("Hello 5555!");
# 变量
$a = 5;
echo $a; // 变量a, 输出5
$b = 8.25;
echo $b; // 不必告知 PHP 变量的数据类型,php会根据它的值,自动把变量转换为正确的数据类型
#空白格子
echo '张三
你在干什么
?
'; // 打印在了一行, 换行用空格隔开, 张三 你在干什么 ?
# 大小写敏感

## 函数不敏感

ECHO "Hello 123!<br>";
echo "Hello 321!<br>";

## 变量敏感

$a="123";
echo "a is " . $a . "<br>"; // 123
echo "A is " . $A . "<br>"; // 空白
#数据类型
## 字符串
$x = "Hello world!";
echo $x; // "Hello world!"
echo "<br>";
$x = 'Hello world!';
var_dump($x); // string(12) "Hello world!"
echo gettype($x); //  string ; gettype获取到变量的类型
## 整数
可以用三种格式规定整数:十进制、十六进制(前缀是 0x)或八进制(前缀是 0)
#浮点数 浮点数是有小数点或指数形式的数字
$x = 10.365;
var_dump($x); // float(10.365)
echo "<br>";
$x = 2.4e3;
var_dump($x); // float(2400)
echo "<br>";
$x = 8E-5;
var_dump($x); // float(8.0E-5)
echo "<br>";
#数组
$cars=array("Volvo","BMW","SAAB");
$_cars=["Volvo","BMW","SAAB"];
var_dump($cars); // array(3) { [0]=> string(5) "Volvo" [1]=> string(3) "BMW" [2]=> string(4) "SAAB" }
var_dump($_cars); // array(3) { [0]=> string(5) "Volvo" [1]=> string(3) "BMW" [2]=> string(4) "SAAB" }

# Null 表示变量无值 NULL 是数据类型 NULL 唯一可能的值 可以通过设置变量值为 NULL 来清空变量数据
$x="Hello world!"; // string(12) "Hello world!"
var_dump($x);
$x=null;
var_dump($x); // NULL

# EOF(heredoc) 定界符

- 以 <<<EOF 开始标记开始,以 EOF 结束标记结束

- 结束标记必须顶头写,独自占一行,不能有缩进和空格

- 在结束标记末尾要有分号

- **EOF** 可以用任意其它字符代替,开始标记和结束标记相同即可,比如常用大写的 EOT、EOD、EOF 来表示,但是不只限于那几个(也可以用:JSON、HTML等),只要保证开始标记和结束标记不在正文中出现即可。

- 位于开始标记和结束标记之间的变量可以被正常解析,但是函数则不可以。在 heredoc 中,变量不需要用连接符 . 或 , 来拼接

- 当内容需要内嵌引号(单引号或双引号)时,不需要加转义符,本身对单双引号转义。

$name="变量会被解析";

$a=<<<EOF
$name<br>
看上面的name已经不是name啦!!!<br>你看看$name "这个"<br>
EOF;

echo $a;
echo "123456 $name 4546";
// 都可以显示变量的值, 使用eof可以在里面使用""不用转义了

$a=<<<EOF
<a>html格式会被解析</a><br/>你看看a标签显示了没?
你看看br显示了没?
<br>
EOF;

echo $a;
echo "<a>html格式会被解析</a><br/>你看看a标签显示了没?
你看看br显示了没?
<br>";
# 转义
echo <<<EOF
"双引号外所有被排列好的格式都会被保留"
"但是双引号内会保留转义符的转义效果,比如table:\t和换行:\n下一行"
你看页面里有\t吗?
\n \t 和引号没关系吧?
那单'引'号呢?'\t \n 是否能看到?'
EOF;
?>
# 运算符
$x=10;
$y=6;

echo -$x; // -10
//整数之间的整除,参数也必须是整数,向下取整
var_dump(intdiv(10, 3)); // int(3)
# 递增递减
echo ++$x; // 输出11 先加再输出
echo $y++; // 输出6  先输出再加

$z=5;
echo --$z; // 输出4

$i=5;
echo $i--; // 输出5
# 等于号  

== 判断值相等 === 判断值和类型都相等  !==

# 逻辑运算符
// &&  运算符的优先级比  and  运算符高。
if (条件)
elseif (条件)
else

循环

# for 循环  
**初始值**和**增量**参数可为空,或者有多个表达式(用逗号分隔)。

for ($i=1,$j=0; $i<=5; ){
     echo "数字为 " . $i.$j . PHP_EOL;
     $i++;
 }

$arr = array("1","2","3","4","5");
$arr = ["1","2","3","4","5"];

var_dump($arr[1]); // string(1) "2"
var_dump($arr[5]); // NULL

$arr1 = [];
$arr1[3] = '3';

var_dump($arr1); // array(1) { [3]=> string(1) "3" }
# 关联数组
$age=["cat"=>"35","dog"=>"37"];
$age['cat']="31";  
$age['dog']="32";

echo $age; // Array
var_dump($age); // array(2) { ["cat"]=> string(2) "31" ["dog"]=> string(2) "32" }
# 获取数组的长度 - count() 函数
echo count($age); // 2
# 遍历
 for($i=0;$i<count($arr);$i++) {
  echo $arr[$i];
  echo "<br>";
 }
 foreach ($age as $value){
  echo $value;
  echo "<br>";
 }

 foreach ($age as $key => $value){
  echo $key;
  echo $value;
  echo "<br>";
 }
# 函数

内置函数  print_r() count() 获取当前时间 time(),date('Y-m-d H:i:s')

 创建(定义)函数 和 调用

    函数的名称应该提示出它的功能

    函数名称以字母或下划线开头(不能以数字开头)

function functionName() {
    // 要执行的代码
}

//调用
functionName();
function plus($a,$b){
   echo $a+$b;
}

plus(2,3); // 5
# 变量作用域
- 在所有函数外部定义的变量,拥有全局作用域
- 除了函数外,全局变量可以被脚本中的任何部分访问
- 要在一个函数中访问一个全局变量,需要使用 global 关键字
- 函数内部声明的变量是局部变量,仅能在函数内部访问

 $lisi="李四";

 function test(){
  global $lisi;
  $age="35";
     echo $lisi; //李四
     echo $age; //35
 }
 test(); // 在外边调test方法是无法打印出方法里面的东西的
 echo $age; // 打印:Array  在外部无法访问到 函数内部的值
# static 作用域

 当一个函数完成时,它的所有变量通常都会被删除。然而,有时候希望某个局部变量不要被删除。

 要做到这一点,请在第一次声明变量时使用 **static** 关键字

function myTest(){

    static $a=0;
    echo $a;
    $a++;
    echo PHP_EOL;    // 换行符
}

myTest(); // 0
myTest(); // 1
myTest(); // 2   如果$a去除static,调用方法3次,都是返回0
# 函数的参数作用域
 function test($li){
   echo $li;
 }

 test('李四'); // 李四
 var_dump($li); // Null  仍是局部变量外部获取不到
# unset和isset函数  unset()可以删除变量,isset() 可以判断变量是否存在
$lisi="李四";

function test(){

    $age="35";
    echo isset($age); // 1
    var_dump(isset($age)); // bool(true)

    unset($age);

    echo isset($age); // 为空
    var_dump(isset($age)); // bool(false)
}

test();
var_dump($lisi); // string(6) "李四"
# 超级全局变量
/*
- $GLOBALS
- $_SERVER
- $_REQUEST
- $_POST
- $_GET
- $_FILES
- $_ENV
- $_COOKIE
- $_SESSION
*/

print_r($GLOBALS);

$lisi1 ="李四";
$age1=35;

function test3(){
    global $lisi1,$age1;
    $age1 = "38";
    $lisi1 = "李四去赶集";
}

test3();

echo $age1;
echo $lisi1;

$lisi2="李四";
$age2=35;

function test4(){
    $GLOBALS["age2"]="38";
    $GLOBALS["lisi2"] = "李四去赶集";
    echo $GLOBALS["lisi2"].'---'.$GLOBALS["age2"]; // 李四去赶集---38
}

test4();
echo PHP_EOL;
echo $age2; // 38
echo $lisi2; // 李四去赶集
运算
# 数组运算符
$a = [
    "a"=>123,
    "b"=>456,
];

$b = [
    "b"=>456,
    "a"=>123,
];

var_dump($a == $b); // true
var_dump($a === $b); // false
# 三元运算
$name = isset($username)?$username:"测试";
// echo isset($username); 为空

var_dump($username); // Null
var_dump($name); // string(6) "测试"
#空合并运算符  ??    

用于简化处理可能为null的变量或数组元素的情况。

它的作用是判断一个变量是否未定义或者为null,如果未定义或为null,则返回指定的默认值;否则返回该变量的值

$name = $username ?? "lisi";

echo $name; // lisi    $username为null所以返回lisi
# 组合比较符 <=>  

可比较整型 浮点型 字符串

$c = $a <=> $b;

// 如果 $a > $b, 则 $c 的值为 1
// 如果 $a == $b, 则 $c 的值为 0
// 如果 $a < $b, 则 $c 的值为 -1

$a = "acd";
$b = "ace";

var_dump($a <=> $b); // int(-1)
# 比较

## 比较undefined、 0、false、null、空值

# empty
$var1 = ""; // 空字符串
$var2 = 0; // 整数0
$var3 = null; // null
$var4 = false; // false
$var5 = array(); // 空数组 []

var_dump(empty($var1)); // true
var_dump(empty($var2)); // true
var_dump(empty($var3)); // true
var_dump(empty($var4)); // true
var_dump(empty($var5)); // true  都是true
# isset()
echo $wangwu;
var_dump(isset($wangwu)); // false  $wangwu是空的
var_dump(!isset($wangwu)); // true   !false
var_dump(is_null($wangwu)); // true  为空
# 字符串相关函数
/*
- strlen()  获取字符串长度
- strpos() 在字符串内查找一个字符或一段指定的文本,返回第一次出现的位置或false
- stripos() 同上,但不区分大小写
- strrpos() 同上上,返回最后一次出现的位置或false
- strripos() 同上,但不区分大小写
- explode()  把字符串打散成数组
- implode() 把数组拼接成字符串
- strtoupper() 把字符串转换为大写
- strtolower() 把字符串转换为小写
- ucfirst() 将单词的首字母转换为大写
- lcfirst() 将单词的首字母转换为小写
- ucwords() 将字符串中每个单词的首字母转换为大写
- str_replace($search, $replace, $string) 将字符串中的某个子字符串替换为另一个字符串
- strrev():将字符串反转
- trim():去除字符串两端的空格
- substr() 截取字符串的一部分
- mb_substr() 截取字符串的一部分(中文)  需要安装扩展mbstring
*/
#数组相关函数
/*
1. array():创建一个数组。
2. count():返回数组中元素的数量。
3. array_push($array, $newElement):将一个或多个元素添加到数组的末尾。
4. array_unshift($array, $newElement):将一个或多个元素添加到数组的开头。
5. array_pop():删除并返回数组中的最后一个元素。
6. array_shift():删除并返回数组中的第一个元素。
7. array_slice():从数组中提取一部分元素,组成新的数组。
8. array_merge():合并两个或多个数组。
9. array_reverse():反转数组中的元素的顺序。
10. in_array():检查数组中是否存在某个值。
11. array_key_exists():检查数组中是否存在某个键。
12. array_keys():返回数组中的所有键,组成新数组。
13. array_values():返回数组中的所有值,组成新数组。
14. array_search():在数组中搜索给定的值,并返回对应的键。
15. array_unique():移除数组中的重复值(原数组不变)。
16. max() min() 最大值和最小值
17. sort() 数组排序(升序)
18. rsort() 数组排序(降序)
19. array_sum() 数组求和
20. array_product() 数组求乘积
*/
# 时间、日期相关知识
# 函数
// - time() 获取当前时间戳(10位),例如:1697520502
// - microtime(true) 返回一个浮点数时间戳(秒数和微秒数的总和)
// - date(格式,时间戳) 日期格式化

$time = time();
echo date('Y-m-d H:i:s',$time); // 2024-08-09 16:41:44

// strtotime(string)
strtotime("next Monday");
$baseTime = strtotime("2023-10-01");
echo strtotime("next Monday", $baseTime); // 1696176000

$baseTime = time();
echo strtotime("+1 day", $baseTime); // 1723279346

// - mktime($hour, $minute, $second, $month, $day, $year)  生成时间戳
// - `date_create()` 来创建一个日期时间对象 `date_create('2023-11-01')`
// - `date_format()` 用于将日期和时间格式化为指定的字符串格式
// date_format($date, "Y-m-d H:i:s");
// date_format($date, "Y年m月d日 H:i:s")
// date_diff() 计算两个日期之间的差

$date1 = date_create('2023-10-20 12:00:00');
$date2 = date_create('2023-10-21 12:00:00');
$diff = date_diff($date2, $date1);
echo $diff->format('%a 天');  echo '<br>'; // 1 天
echo $diff->format('%m 月');  echo '<br>'; // 0 月
echo $diff->format('%y 年 %m 月 %d 天');  echo '<br>'; // 0 年 0 月 1 天

// -  %Y :完整年份的差异
// -  %y :年份的差异(两位数)
// -  %m :月份的差异
// -  %d :天数的差异
// -  %a :总共的天数差异
// -  %H :小时的差异
// -  %h :小时的差异(12小时制)
// -  %I :分钟的差异
// -  %S :秒数的差异
// -  %R :正负
// -  %r :正负(必须是负的才会显示)
// `strftime($format, $timestamp)` :根据指定的格式,将时间戳格式化为可读的日期和时间字符串,支持本地化的日期和时间格式 (php8已废弃)。
// - `gmdate($format, $timestamp)` :根据指定的格式,将GMT时间戳格式化为可读的日期和时间字符串。
//   `gmdate()` 和 `date()`的区别
//   `gmdate()` 函数使用格林威治标准时间(GMT)作为默认的日期/时间基准,会忽略服务器的时区设置,始终返回格林威治标准时间(GMT)的日期和时间;
//   `date()` 函数则使用本地时间作为基准,它会根据当前服务器的时区设置来格式化日期和时间。
// - `date_default_timezone_set($timezone)` :设置默认的时区。
// "UTC", "localtime"本地时区, "Asia/Shanghai"上海
// 注意:只能在脚本开始时设置默认时区,不能在运行时动态设置。
// - `timezone_identifiers_list()` :返回所有可用时区标识符的数组。

#### DateTime对象
// $dateTime = new DateTime("2023-11-01 12:34:56");
// //增加或减少指定的时间间隔
// $dateTime->modify('+1 day');
// $dateTime->modify('-1 hour');
// //设置日期部分 setDate($year, $month, $day)
// $dateTime->setDate(2024, 1, 3);
// //设置时间部分 setTime($hour, $minute, $second)
// $dateTime->setTime(13, 1, 5);
// // 设置时区
// $dateTime->setTimezone(new DateTimeZone("Asia/Shanghai"));
// // 获取时区
// $dateTimeZone = $dateTime->getTimezone();
// print_r($dateTimeZone->getName());
// print_r($dateTimeZone->getLocation());
// //将日期时间格式化为指定的字符串格式
// echo $dateTime->format("Y-m-d H:i:s");
// //获取时间戳
// $timestamp = $dateTime->getTimestamp();
// echo $timestamp;

// //计算时间差
// $dateTime2 = new DateTime('2023-12-05');
// $diff = $dateTime->diff($dateTime2);
// echo $diff->format('%R %m %d %h %i %s');
// $datetime = new DateTime('2024-01-01');
// $interval = new DateInterval('P1D'); // 一天的时间间隔
// $datetime->add($interval);
// $datetime->sub($interval);
// echo $datetime->format('Y-m-d');
# 常量  

常量值被定义后,在脚本的其他任何地方都不能被改变。

命名规则和变量类似,严格区分大小写,但无需$符

默认是全局的,可以在整个运行的脚本的任何地方使用。

define("lisi", "李四冲啊");

#const和define的区别    const不能在条件语句中定义常量
$a = 1;

define("liuzi".$a, "liuzi 1");

if($a==1){
    define("liuzi".$a, "liuzi 2");
    echo constant("liuzi".$a); // liuzi 1   因为是常量, 无法改变
    // const laoliu = "老六";
    // echo laoliu;  // 会报错 const不能在条件语句中定义常量
}

// - const用于类成员变量的定义,define不可以用于类成员变量的定义,可用于全局常量。
// - const可在类中使用,define不能

class test6 {
    const zhaoliu = '李四';
    // define('wang','王'); // 报错  不能在类中使用
    public function cc()
    {
        define('li','李');
        // const shudian = '水电费撒旦法';  会报错  不能在函数中使用
        echo self::zhaoliu; // 李四
    }
}

$c = new test6;
$c->cc();

echo li; // 李

// echo wang; // 李
// echo zhaoliu; // 报错
#常量和变量的区别:

// - 常量前面没有美元符号($),而且不能有

// - 常量可以不用理会变量的作用域在任何地方定义和访问

// - 常量一旦定义就不能重新定义或取消定义

// - 常量的值只能是标量(字符串、整数、浮点数、布尔值),注意:现在也支持数组了

// 获取所有的常量
// get_defined_constants()
// get_defined_constants(true)
// get_defined_constants(true)["user"]
# 魔术常量  

它的值随着它在代码中的位置改变而改变

// `__LINE__`       文件中的当前行号
echo '这是第 " ' . __LINE__ . ' " 行'; // 这是第 " 548 " 行

// __FILE__    文件的完整路径和文件名,包含(盘符)根目录
echo '该文件的完整路径为 " ' . __FILE__ . ' " '; 
// F:\aaaaaaaaaaaaaaaaaaa\pp\phpstudy_pro\WWW\demo.cn\index.php "

// `__DIR__`  文件所在的目录
echo '该文件位于 " ' . __DIR__ . ' " '; 
// F:\aaaaaaaaaaaaaaaaaaa\pp\phpstudy_pro\WWW\demo.cn "

// `__FUNCTION__`    该函数被定义时的名字(区分大小写)
function test7() {
    echo  '函数名为:' . __FUNCTION__ ; // 函数名为:test7
}
test7();

// `__CLASS__`    该类被定义时的名字(区分大小写)
class testClass {
    function test() {
        echo '类名为:'  . __CLASS__ . "<br>";  // testClass
        echo  '函数名为:' . __FUNCTION__ ;  // 函数名为:test
    }
}
$t = new testClass();
$t->test();

// `__NAMESPACE__`     命名空间
// namespace MyProject;
// echo '命名空间为:"', __NAMESPACE__, '"'; // 输出 "MyProject"

// `__METHOD__`  包含了:命名空间 类名 函数名
// namespace MAOSHU;
// class MyClass {
//     public function myMethod() {
//         echo __METHOD__; // 输出:MAOSHU\MyClass::myMethod
//     }
// }
// $obj = new MyClass();
// $obj->myMethod();

//  `__TRAIT__`   当前使用的 trait 的名称
// trait MyTrait {
//     public function myMethod() {
//         echo "trait的名称为: " . __TRAIT__;
//     }
// }

// class MyClass {
//     use MyTrait;
// }

// $obj = new MyClass();
// $obj->myMethod();
# 包含文件

 include 和 require 语句

 **include 和 require 除了处理错误的方式不同之外,在其他方面都是相同的:**

- require 生成一个致命错误(E_COMPILE_ERROR),在错误发生后脚本会停止执行。

 - include 生成一个警告(E_WARNING),在错误发生后脚本会继续执行。

// 因此:
// 如果你希望被包含的文件是必需的且缺少文件会导致脚本无法正常运行,应使用require(推荐)。
// 如果你希望被包含的文件是可选的,或者即使缺少文件也希望脚本继续执行,可以使用include。
    $siteTitle = "猫叔星球(maoshu.fun)";
<?php echo $siteTitle;?>

<!-- ### include_once 和 require_once 语句
和上面的一样,但他只会调用一次,防止重复调用 -->

面向对象(OO)

类(class)

类的定义和调用
类的定义
class Animal {
    public $name = "小猫仔";
    public function eat() {
        echo " 在吃饭.";
    }
}
类的调用
new 实例化对象
$cat = new Animal;
//$cat = new Animal();
echo $cat->name;
$cat->eat();
方法和属性
类方法(函数)
class Animal {
    public $name = "小猫仔";
    public function eat() {
        echo " 在吃饭.";
    }
    function say() {
        echo " 在说话.";
    }
}
$this

代表自身的对象

class Animal {
    public $name = "小猫仔";
    public function eat() {
        echo $this->name." 在吃饭.";
    }
    function say() {
        echo $this->name." 在说话.";
    }
}
​
$cat = new Animal;
$cat->name = "小花";
$cat->say();
​
$dog = new Animal;
$dog->name = "小黑";
$dog->say();
访问控制

关键字 public、private、protected

  • protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问

__construct构造函数
  • 构造函数是一种特殊的方法,在创建一个新对象时,它会被自动调用。

  • 它可以用来 初始化 对象的属性或执行其他必要的操作

  • 没有返回值

  class Animal {
    private $name;
    private $birth;
    private $age;
​
    public function __construct($name,$birth)
    {
        $this->name = $name;
        $this->birth = $birth;
        
        $days = (time() - strtotime($this->birth))/3600/24;
        $this->age = floor($days);
    }
​
    public function eat() {
        echo  $this->name." 在吃饭.";
    }
}
​
$cat = new Animal("猫仔","2023-05-23");
echo $cat->name;
echo ' -- ';
echo $cat->birth;
echo ' -- ';
echo $cat->age;
__destruct析构函数
  • 析构函数是一种特殊的方法,它在对象被销毁时自动调用

  • 它可以用来执行一些清理操作,例如释放资源或关闭数据库连接。

  • 当对象不再被引用或脚本执行结束时,析构函数会被自动调用。

class MyClass {
    public function say($i)
    {
      echo 'saying-'.$i;
    }
    public function __destruct() {
        echo "析构函数被调用\n";
    }
}
​
// 创建对象
$obj = new MyClass();
​
// 执行其他操作...
for ($i=0; $i < 4; $i++) {
    if($i==3){
        unset($obj);
    }
    if($obj)
        $obj->say($i);
}
static 静态变量 和 self

「静态」指的是无需对类进行实例化,就可以直接调用这些属性和方法 所有对静态变量进行的操作都会对所有对象起作用 举例:小猫小狗听到指令来吃饭,指令变化,全部都要听从

public static $cat = "猫叔";
​
echo self::$cat;
类常量

静态属性与类常量相似,唯一的区分是类常量不可以更改,静态属性可以更改 使用场景:所有的对象共用一个属性

const MAOSHU = "猫叔";
​
echo self::MAOSHU;
static 静态方法
public static function say() {
        echo self::$name;
}

可以调用静态方法、静态变量 可以调用非静态方法、非静态变量

public function eat() {
        echo $this->name." 在吃饭.";
}
public static function say() {
        echo (new self)->eat();
}
类的继承(extends):

指可以创建一个新的类,该类继承(extends)了父类的属性和方法,并且可以添加自己的属性和方法。通过继承,可以避免重复编写相似的代码,并且可以实现代码的重用。

注意:继承不一定能访问

class Animal {
    public $name="小动物";
    protected $age=3;
    private $birth='2023';
}
​
class Cat extends Animal {}
​
​
var_dump(new Animal);
var_dump(new Cat);
class Animal {
    protected $name;
​
    public function __construct($name) {
        $this->name = $name;
    }
​
    public function eat() {
        echo $this->name . " 在吃饭.";
    }
}
​
class Cat extends Animal {
    public function meow() {
        echo $this->name . " 在喵呜.";
    }
}
​
$cat = new Cat("Tom");
var_dump($cat);
$cat->eat();  // 继承自父类 Animal 的方法
$cat->meow();  // 子类 Cat 自己的方法
方法和属性重写

如果从父类继承的方法或属性不能满足子类的需求,可以对其进行改写

final 关键字

作用:

  • 防止类被继承

  • 防止类的方法被重写

如果在一个类前加final,那么这个类就不能被继承;

final class myClass {
    // 类的内容
}

如果在一个方法前加final,那么这个方法就不能被重写

    final public function eat() {
        echo $this->name . " 在吃饭.";
    }

注意:final不能用于属性

调用父类方法
parent:: parent::__construct()
静态延迟绑定 static

是指在运行时根据实际调用的类来确定静态方法或属性的绑定 语法:static::$name

class Animal {
    protected static $name="小动物";
​
    public static function eat() {
        echo self::$name. " 在吃饭.";
        echo ' ---- ';
        echo static::$name. " 在吃饭.";
    }
}
​
class Cat extends Animal {
    protected static $name="小猫";
}
​
Animal::eat();
Cat::eat();
​
类的多态
  • 多态性允许不同类的对象对相同的消息作出不同的响应。

  • 多态性通过方法重写(覆盖)和方法重载来实现。

  • 方法重写是指子类重写父类的方法,以改变方法的实现细节。

  • 方法重载是指在同一个类中根据参数个数或类型不同来实现不同功能。

  • 需要注意的是,多态性只适用于继承关系的类。子类必须重写父类的方法才能实现多态性。

class Animal {
    protected $name="动物";
    public function makeSound() {
        echo "$this->name 在吼叫。";
    }
}
​
class Dog extends Animal {
    protected $name="小狗";
    public function makeSound() {
        echo "$this->name 在汪汪。";
    }
}
​
class Cat extends Animal {
    protected $name="小猫";
    public function makeSound() {
        echo "$this->name 在喵喵。";
    }
}
​
$animal = new Animal();
$dog = new Dog();
$cat = new Cat();
​
$animal->makeSound();
$dog->makeSound();
$cat->makeSound();
方法重载
$args = func_get_args(); 
$numArgs = func_num_args();
​
function test(){
​
    $args = func_get_args(); 
    $numArgs = func_num_args();
    
    var_dump($args[1]);
    var_dump($numArgs);
}
​
test(1,2,3,4);
​
class Animal {
    public function makeSound() {
        echo "动物在吼叫";
    }
}
​
​
class Cat extends Animal {
    public function makeSound() {
        // $args = func_get_args();
        $numArgs = func_num_args();
        
        switch($numArgs){
            case 2:
                echo '执行参数个数为2的事件';
                break;
            case 3:
                echo '执行参数个数为3的事件';
                break;
            default:
                echo '执行默认事件';
        }
    }
}
​
// $animal = new Animal();
$cat = new Cat();
​
$cat->makeSound("测试","2");
接口和抽象类
interface(接口)
interface Animals {
    public function a();
    public function b();
}
​
class Cat implements Animals {
    public function a(){
    
    };
    public function b(){
    
    };
}

接口是指一组方法的集合,不是类,不能被实例化。

  • 可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容

  • 只可以使用public

  • 通常用于定义一些规范,让代码更加有条理 不易出错。 例如:小动物必须要吃饭和睡觉,否则就会死!这是必须的,每个小动物都必须有这2个方法!

interface Animals {
    const MAOSHU = "猫叔";
    public function eat();
    public function sleep($hours);
    public static function jump();
}
  
class Cat implements Animals {
    public function eat() {
        echo "Cat 在吃饭.";
    }
​
    public function sleep($hours) {
        echo "Cat 要睡 $hours 小时.";
    }
​
    public static function jump(){
        echo '跳跳跳';
    }
}
​
$cat = new Cat();
$cat->eat();
$cat->sleep(18);
​
echo Cat::MAOSHU;
echo Cat::jump();
interface Animals {
    public function eat();
    public function sleep($hours);
}
interface Sports {
    public function run();
    public function jump();
}
class Cat implements Animals,Sports {
    public function eat() {
        echo "Cat 在吃饭";
    }
​
    public function sleep($hours) {
        echo "Cat 要睡 $hours 小时";
    }
​
    public function run() {
        echo "Cat 在跑步";
    }
​
    public function jump() {
        echo "Cat 在蹦跳";
    }
}
抽象类和抽象方法

和接口非常类似,使用它也是定义一种约束或规范,适合较大型的项目或库使用

抽象类
abstract class Animals{
​
}
  • 抽象类是一种特殊的类,只能被继承,不能被实例化

  • 抽象类用于定义一组相关的方法,但这些方法的具体实现由继承它的子类来完成。

  • 子类继承抽象类后,必须实现抽象类中的所有抽象方法。

  • 抽象类可以包含抽象方法和普通方法

抽象方法
abstract public function xxx();
abstract protected function xxx();
  • 抽象方法是没有具体实现的方法,只有方法的声明,而不需要方法体。

  • 抽象方法只能存在于抽象类中。

  • 可以使用protected,但不能使用private私有。

abstract class Animals
{
    abstract public function eat();
    abstract protected function sleep($hours);
​
    public function play()
    {
      echo '玩耍';
    }
}
​
class Cat extends Animals
{
    public function eat()
    {
        echo "Cat 在吃饭.";
    }
​
    protected function sleep($hours)
    {
        echo "Cat 要睡 $hours 小时.";
    }
}
​
​
$cat = new Cat();
$cat->eat();
//$cat->sleep(12);
$cat->play();
抽象类与接口的区别
  1. 抽象类可以包含非抽象方法的实现,而接口只能包含方法的声明,没有方法的实现。

  2. 类只能继承一个抽象类,但可以实现多个接口。

  3. 抽象类可以有构造函数,而接口不能有构造函数。

  4. 抽象类中的方法可以有public、protected和private访问修饰符,而接口中的方法只能是public。

  5. 子类继承抽象类时,必须实现抽象类中的所有抽象方法,否则子类也必须声明为抽象类。 子类实现接口时,必须实现接口中的所有方法。

trait代码复用
  • 解决类的单一继承问题

  • 可同时使用多个trait,用逗号隔开

  • 把常用的、通用的代码抽离出来,写成trait

trait A{
​
}
trait B{
​
}
class C {
    use A,B;
}

和类的继承非常像,但是trait里面不能有类常量,且trait不能被实例化。 根据下面类的继承来修改,对比看下他们的相同点:

class Animal {
    protected $name;
    const MAOSHU="猫叔";
​
    public function __construct($name) {
        $this->name = $name;
    }
​
    public function eat() {
        echo $this->name . " 在吃饭.";
    }
}
​
class Cat extends Animal {
    public function meow() {
        echo $this->name . " 在喵呜.";
    }
}
​
$cat = new Cat("Tom");
var_dump($cat);
$cat->eat();  // 继承自父类 Animal 的方法
$cat->meow();  // 子类 Cat 自己的方法
  • trait中可使用抽象方法

  • trait中可使用静态属性和静态方法

  • trait中可使用其他trait

  • trait中可使用parent

class MainClass{
    public function main()
    {
      echo '这是主方法的'.__METHOD__;
    }
}
trait Animal {
​
    public function eat() {
        parent::main();
        echo $this->name . " 在吃饭.";
        echo __TRAIT__;
    }
}
​
class Cat extends MainClass {
    use Animal;
    protected $name;
    public function __construct($n) {
        $this->name = $n;
    }
    public function meow() {
        echo $this->name . " 在喵呜.";
        echo __TRAIT__;
    }
}
​
$cat = new Cat("Tom");
var_dump($cat);
$cat->eat();  // 继承自父类 Animal 的方法
echo '----';
$cat->meow();  // 子类 Cat 自己的方法
同名冲突

当一个类同时引入了多个Trait,并且这些Trait中存在同名方法时,就会产生方法冲突。

use A,B{
    //A::eat insteadof B;
    B::eat insteadof A;
    //别名定义
    A::eat as Aeat;
}
trait A
{
    public function eat(){
        echo '这是A的';
    }
}
​
trait B
{
    public function eat(){
        echo '这是B的';
    }
}
​
class T{
    use A,B{
        A::eat insteadof B;
        B::eat as Beat;
    }
}
​
$t = new T;
​
$t->eat();
$t->Beat();

表单和请求

主要用到了$_GET$_POST超全局变量,分别对应两种不同的请求方式

表单
input select radio checkbox submit

<form action="./user.php" method="post">
    用户名: <input type="text" name="username">
    密码: <input type="text" name="password">
    <select multiple name="arr[]">
        <option value="">请选择:</option>
        <option value="1">大猫</option>
        <option value="2">二猫</option>
        <option value="3">三猫</option>
    </select>
    <input type="submit" value="提交">
</form>

关于网络请求

GET请求和POST请求是两种常用的HTTP请求方法,用于从客户端向服务器发送数据

GET请求:

通过URL(网址)参数将数据附加在URL上发送给服务器。这些参数以键值对的形式出现在URL的末尾,使用问号"?"将URL和参数分隔开。

POST请求:

将数据作为请求的主体发送给服务器,而不是附加在URL上。这使得POST请求更适合发送敏感数据或超长大段内容,例如表单中的密码、博客文本内容等。

区别:
  • GET参数对任何人都是可见的,POST参数对任何人都是不可见的

  • GET对发送信息的量也有限制,不适合大型的变量值,它的值不能超过 2000 个字符;POST对发送信息的量没有限制(默认POST 发送的最大值为 8 MB,但可通过设置 php.ini 的 post_max_size 进行更改;发送的变量数最大值max_input_vars)

  • 可以在收藏夹中收藏GET请求页面,或者发送带参数的网址给别人可以直接访问,例如带页码的网址、带商品id的淘宝商品、带文章id的博文。这一点POST做不到。

超全局变量$_REQUEST

$_REQUEST 变量包含了 $_GET$_POST$_COOKIE 的内容 $_SERVER获取请求方式

htmlspecialchars()函数

用于将字符串中的特殊字符转换为HTML实体,以避免在HTML文档中引起解析错误或安全漏洞。

  • & (和号) 成为 &amp;

  • " (双引号) 成为 &quot;

  • ' (单引号) 成为 &#039;

  • < (小于) 成为 &lt;

  • > (大于) 成为 &gt;

mysql数据库

本课程只讲解最简单的增删改查语句,不做更深入的语句讲解。

配置环境变量

mysql -u root -p

查看数据库列表: SHOW DATABASES;

使用数据库 USE xxx;

查看数据表列表: SHOW TABLES;

数据库工具:SQL_Front(小皮内置)、Navicat、DBeaver

操作数据库的方式:MySQLi 和 PDO

MySQLi

首先要启用扩展mysqli

面向过程

<?php
$servername = "localhost";
$username = "root";
$password = "root";
 
// 创建连接
$conn = mysqli_connect($servername, $username, $password);
 
// 检测连接
if (!$conn) {
    die("连接失败: " . mysqli_connect_error());
}
echo "连接成功";
​
//关闭
mysqli_close($conn);
?>

面向对象

<?php
$servername = "localhost";
$username = "root";
$password = "root";
 
// 创建连接
$conn = new mysqli($servername, $username, $password);
 
// 检测连接
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
} 
echo "连接成功";
​
//关闭
$conn->close();
?>
resource 资源类型
  • is_resource() 是否为资源类型

  • get_resource_type() 获取资源的类型名称

$servername = "localhost";
$username = "root";
$password = "root";
$conn = mysql_connect($servername, $username, $password);
var_dump(is_resource($conn));
var_dump(gettype($conn));
var_dump(get_resource_type($conn));
$handle = fopen("test.txt", "r");
var_dump($handle);
var_dump(is_resource($handle));
var_dump(gettype($handle));
var_dump(get_resource_type($handle));
​
//$content = fread($handle, filesize("test.txt"));
//echo $content; 
fclose($handle);

接下来将主讲面向对象方式操作

创建数据库
// 创建数据库
$sql = "CREATE DATABASE IF NOT EXISTS maoshuDB";
//if (mysqli_query($conn, $sql)) {
if ($conn->query($sql) === TRUE) {
    echo "数据库创建成功";
} else {
    echo "数据库创建失败 " . $conn->error;
}
创建数据库表
  • NOT NULL - 每一行都必须含有值(不能为空),null 值是不允许的。

  • DEFAULT value - 设置默认值

  • UNSIGNED - 使用无符号数值类型,0 及正数

  • AUTO INCREMENT - 设置 MySQL 字段的值在新增记录时每次自动增长 1

  • PRIMARY KEY - 设置数据表中每条记录的唯一标识。 通常列的 PRIMARY KEY 设置为 ID 数值,与 AUTO_INCREMENT 一起使用。

每个表都应该有一个主键(本列为 "id" 列),主键必须包含唯一的值。

//$conn->query("USE maoshuDB");
// 使用 sql 创建数据表
$sql = "CREATE TABLE IF NOT EXISTS user (
  id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
  username VARCHAR(30) NOT NULL COMMENT \"用户名\",
  password VARCHAR(64) NOT NULL COMMENT '密码',
  phone VARCHAR(11),
  status INT(1) NOT NULL DEFAULT 1,
  create_date TIMESTAMP
  ) COMMENT '用户'";
//if (mysqli_query($conn, $sql)) {
if ($conn->query($sql) === TRUE) {
    echo "数据表创建成功";
} else {
    echo "数据表创建错误: " . $conn->error;
}

注:如果要加注释,那么后面加上 COMMENT 即可

插入数据

注意: 如果列设置 AUTO_INCREMENT (如 "id" 列) 或 TIMESTAMP (如 "create_date" 列),我们就不需要在 SQL 语句中指定值; MySQL 会自动为该列添加值。

INSERT INTO table_name (column1, column2, column3,...)
VALUES (value1, value2, value3,...)

$conn->query($sql) === TRUE来判断是否插入成功

$sql = "INSERT INTO user (username, password, phone)
VALUES ('da mao', '123456', 13888888888)";
//if (mysqli_query($conn, $sql)) {
if ($conn->query($sql) === TRUE) {
    echo "新记录插入成功";
} else {
    echo "错误: " . $sql . "<br>" . $conn->error;
}
字符串进行转义处理

$conn->real_escape_string($string); 可以确保特殊字符被正确转义,从而避免了SQL注入等安全问题,并保证查询语句的语法正确性,例如:

$name="这是一个'送命题'";
插入多条数据
$sql = "INSERT INTO user (username, password, phone)
VALUES 
    ('大猫', '123456', 13888888888),
    ('小猫', '123456', 13888888887),
    ('中猫', '123456', 13888888886)
    ";
$conn->query($sql);

foreach循环插入,或者使用语句: mysqli_multi_query()

$sql = "INSERT INTO user (username, password, phone)
VALUES ('大猫', '123456', 13888888888);";
​
$sql .= "INSERT INTO user (username, password, phone)
VALUES ('小猫', '123456', 13888888887);";
​
$sql.= "INSERT INTO user (username, password, phone)
VALUES ('中猫', '123456', 13888888886);";
​
//if (mysqli_multi_query($conn, $sql)) {
if ($conn->multi_query($sql) === TRUE) {
    echo "新记录插入成功";
} else {
    echo "错误: " . $sql . "<br>" . $conn->error;
}
查询数据
SELECT column1,column2 FROM table_name
$sql = "SELECT * FROM user";
$result = $conn->query($sql);
//if (mysqli_num_rows($result) > 0) {
if ($result->num_rows > 0) {
    echo "$result->num_rows 条结果";
    // 输出数据
    //while($row = mysqli_fetch_assoc($result)) {
    while($row = $result->fetch_assoc()) {
        echo "id: " . $row["id"]. " - Name: " . $row["username"]. " " . $row["phone"]. "<br>";
    }
} else {
    echo "0 条结果";
}
  • $result->num_rows 获取到的数据条数

  • $result->fetch_assoc() 是一种用于从结果集中获取一行数据的函数。它以关联数组的形式返回结果,其中列名作为键,对应的值则是该行中各列的值

  • 除了fetch_assoc 还有 fetch_row和fetch_array和fetch_all

while($row = $result->fetch_row()) {
    echo "id: " . $row[0]. " - Name: " . $row[1]. " " . $row[2]. "<br>";
}
    //$datas = mysqli_fetch_all($result, MYSQLI_ASSOC);
    $datas = $result->fetch_all(MYSQLI_ASSOC);
    var_dump($datas);

free_result()

释放结果集所占用的内存资源。在使用 query() 函数执行查询后,会返回一个结果集对象,该结果集对象占用一定的内存空间。

//mysqli_free_result($result);
$result->free_result();
where 条件筛选

WHERE用于在查询中指定筛选条件,来限制返回的行

SELECT 列名
FROM 表名
WHERE 条件;

条件判断: > < = != <> >= <= like "%xxx%" like "%xxx" like "xxx%" between and is null is not null in (a,b,c)

and or not 括号

order by 排序

ASC升序 、DESC降序 根据两列进行排序,用逗号隔开即可,注意:只有第一列的值相同时才使用第二列

offset limit
SELECT 列名
FROM 表名
LIMIT 行数 OFFSET 偏移量;
更新数据
UPDATE 表名
SET column1=value, column2=value2,...
WHERE 条件

注意:如果省去 WHERE 子句,所有的记录都会被更新

使用计算表达式更新字段

UPDATE 表名 SET 列名 = 列名 + 值 WHERE 条件;
$sql = "UPDATE user SET num = num*3 WHERE id = 2";
$result = $conn->query($sql);
删除数据
DELETE FROM 表名
WHERE 条件

注意:如果省去 WHERE 子句,所有的记录都会被删除

删除表中的重复行

DELETE t1 FROM 表名 t1, 表名 t2 WHERE t1.列名 = t2.列名 AND t1.id > t2.id;
修改数据表
修改数据表名:
ALTER TABLE 旧表名 RENAME 新表名;
​
重置自增起始值为1:
ALTER TABLE 表名 AUTO_INCREMENT = 1;
​
添加新的列:
ALTER TABLE 表名 ADD COLUMN 列名 数据类型;
​
修改列名和数据类型:
ALTER TABLE 表名 CHANGE COLUMN 旧列名 新列名 新数据类型;
​
修改列的默认值: 
ALTER TABLE 表名 ALTER COLUMN 列名 SET DEFAULT 默认值;
​
删除列:
ALTER TABLE 表名 DROP COLUMN 列名;
​
修改列的注释:
ALTER TABLE 表名 MODIFY COLUMN 列名 数据类型 COMMENT '新注释';
​
删除数据表:
DROP TABLE IF EXISTS 表名
​
清空数据表:
TRUNCATE TABLE 表名;
​
删除数据库:
DROP database

咱们只讲了最基本的mysql,关于关联查询 索引 等更深入的知识就需要专门学习了。

预处理语句

预处理语句(Prepared Statements),用于执行带有参数的SQL语句。

  • 预处理语句可以提高安全性,对于防止 SQL 注入是非常有用的

  • 允许重复使用相同的sql模板而只需更改参数,提高执行效率。

关于sql注入

当涉及到SQL查询时,注入攻击是一种常见的安全漏洞

1. 直接执行用户输入的SQL查询:
$query = $_GET['query'];
$result = $conn->query($query);

如果用户能够直接执行他们自己构造的SQL查询,就会产生严重的安全问题。恶意用户可以执行任意的SQL语句,包括删除、修改或泄露敏感数据。

2. 使用字符串拼接的方式构建SQL查询:
$username = $_POST['username'];
$password = $_POST['password'];
​
$sql = "SELECT * FROM user WHERE username = '" . $username . "' AND password = '" . $password . "'";
$result = $conn->query($sql);

这种方式存在安全风险,如果用户在输入框中输入恶意代码,可以破坏原始的SQL查询结构,例如输入 ' OR 1=1 -- ,会导致查询条件永远为真,从而绕过身份验证。

  1. 转义特殊字符也不保险:

$username = $conn->real_escape_string($_POST['username']);
$password = $conn->real_escape_string($_POST['password']);
​
$query = "SELECT * FROM users WHERE username = '" . $username . "' AND password = '" . $password . "'";
$result = $conn->query($query);

我们使用 ->real_escape_string() 函数对用户输入的用户名和密码进行转义,以防止SQL注入,但仍然可能存在注入漏洞。 假设用户在用户名输入框中输入 admin'-- ,并在密码输入框中输入任意值。由于转义字符未正确处理,生成的SQL查询语句如下

SELECT * FROM users WHERE username = 'admin'--' AND password = 'password'

在这种情况下, -- 是SQL注释的开始,后面的 AND password = 'password' 将被忽略。这样,攻击者可以绕过密码验证并成功登录,即使没有提供正确的密码。

预处理方法

查询

$sql = "SELECT * FROM user WHERE username = ? AND password = ? ";
$stmt = $conn->prepare($sql);
//绑定
$stmt->bind_param("ss", $username, $password);
//执行
$stmt->execute();
​
//获取结果
$result = $stmt->get_result();
print_r('<pre>');
print_r($result->fetch_all());
​
//关闭
$stmt->close();

插入

// 预处理
$sql = "INSERT INTO user (username, password, phone)
VALUES (?, ?, ?)";
$stmt = $conn->prepare($sql);
//绑定
$stmt->bind_param("sss", $username, $password, $phone);
//执行
$stmt->execute();
​
//获取结果
if ($stmt->affected_rows > 0) {
    echo "插入成功";
} else {
    echo "插入失败";
}
​
​
//关闭
$stmt->close();

其中的?为占位符

通过告诉数据库参数的数据类型,可以降低 SQL 注入的风险。参数有以下四种类型:

  • i - integer(整型)

  • d - double(双精度浮点型)

  • s - string(字符串)

  • b - BLOB(binary large object:二进制大对象)

每个参数都需要指定类型。

php8新方法

$name="这是一个'送命题'";
//mysqli_execute_query
$sql = "INSERT INTO user (username, password, phone)
VALUES (?, ?, ?)";
$conn->execute_query($sql,[$name,'123456','13888888888']);
$conn->execute_query($sql,[$name,'123456','13888888888']);

PDO

安装php_pdo_mysql扩展,用phpinfo() 函数来查看是否安装了PDO扩展

PDO执行sql语句分为2种方法:

exec() 方法:

  • 适用于执行不返回结果集的SQL语句,例如INSERT、UPDATE和DELETE等操作。

  • exec() 方法返回受影响的行数(即被插入、更新或删除的行数),如果没有受影响的行,返回0。

  • 通常用于执行不需要获取结果集的简单操作。

query() 方法:

  • 适用于执行返回结果集的SQL语句,例如SELECT查询。

  • query() 方法返回一个PDOStatement对象,你可以使用该对象的方法(如 fetch() 、 fetchAll() )来获取查询结果。

  • 通常用于执行需要获取结果集的查询操作。

创建连接
<?php
$dbms='mysql';     //数据库类型
$host='localhost'; //数据库主机名
$dbName='maoshudb';    //使用的数据库
$user='root';      //数据库连接用户名
$pass='root';          //对应的密码
$dsn="$dbms:host=$host;dbname=$dbName";
​
try {
    $conn = new PDO($dsn, $user, $pass); //初始化一个PDO对象
    echo "连接成功<br/>";
    // 关闭连接
    $conn = null;
} catch (PDOException $e) {
    die ("错误!: " . $e->getMessage() . "<br/>");
}
?>
创建数据库
    //设置 PDO 错误模式为异常
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    //PDO::ERRMODE_WARNING 警告
    //PDO::ERRMODE_SILENT 错误码
    //$conn->errorCode()
    //$conn->errorInfo()
​
    // 创建数据库
    $sql = "CREATE DATABASE 数据库名";
    $conn->exec($sql);
    echo "数据库创建成功";
创建数据表
    $sql = "CREATE TABLE IF NOT EXISTS user6 (
        id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
        username VARCHAR(30) NOT NULL COMMENT \"用户名\",
        password VARCHAR(64) NOT NULL COMMENT '密码',
        phone VARCHAR(11),
        status INT(1) NOT NULL DEFAULT 1,
        create_date TIMESTAMP
        ) COMMENT '用户'";
    $conn->exec($sql);
查询数据
    // 执行查询语句
    $sql = "SELECT * FROM user WHERE id<5";
    $result = $conn->query($sql);
​
    // 获取结果
    $result = $result->fetchAll(PDO::FETCH_ASSOC);
    var_dump($result);
更新数据
    $sql = "UPDATE user SET num = num+3 WHERE id =2";
    $stmt = $conn->exec($sql);
    var_dump($stmt);
删除数据
	$sql = "DELETE FROM user WHERE id =26";
    $stmt = $conn->exec($sql);
插入数据

和mysqli的类似,不做特殊说明了 预处理

    // 执行插入语句
    $sql = "INSERT INTO 表名 (列1, 列2, 列3) VALUES (:value1, :value2, :value3)";
    $stmt = $conn->prepare($sql);
​
    // 绑定参数
    $stmt->bindParam(':value1', $value1);
    $stmt->bindParam(':value2', $value2);
    $stmt->bindParam(':value3', $value3);
​
    // 设置参数值
    $value1 = "值1";
    $value2 = "值2";
    $value3 = "值3";
​
    // 执行插入语句
    $stmt->execute();
    
    // 获取插入的条数
    $rowCount = $stmt->rowCount();

批量插入

    $sql = "INSERT INTO user (username, password, phone) VALUES (?,?,?)";
    $stmt = $conn->prepare($sql);
​
    // 执行插入语句
    $stmt->execute(["test1","1234","13888888888"]);
    $stmt->execute(["test2","1232","13888888888"]);
事务

事务(Transaction)是一组数据库操作的集合,这些操作要么全部成功执行,要么全部回滚(撤销)。事务提供了一种机制来确保数据库操作的一致性和完整性。

    try {
        // 开始事务
        $conn->beginTransaction();
    
        // 执行批量插入语句
        $sql = "INSERT INTO user (username, password, phone) VALUES (?,?,?)";
        $stmt = $conn->prepare($sql);
    
        $data = array(
            array("值1", "值2", "值3"),
            array("值4", "值5", "值6"),
            array("值7", "值8", "值9")
        );
        
        $insertedRows = 0;
        foreach ($data as $row) {
            $stmt->execute($row);
            $insertedRows += $stmt->rowCount();
        }
    
        // 提交事务
        $conn->commit();
    
        echo "批量插入成功";
    } catch(PDOException $e) {
        // 回滚事务
        $conn->rollback();
        echo "插入失败: " . $e->getMessage();
    }

作业:把PDO里没有用预处理的改为预处理方式。如果有时间,可以把上面的增删改查封装为一个DB类,方便调用。 后面我们实战的时候也会讲PDO类的二次封装和调用。

cookie session

cookie

cookie 常用于识别用户。 cookie 是一种服务器留在用户计算机上的小文件。 每当同一台计算机通过浏览器请求页面时,这台计算机将会发送 cookie。 通过 PHP,能够创建并取回 cookie 的值。

创建cookie
setcookie(name, value, expire, path, domain);

参数说明:

  • name :Cookie的名称。

  • value :Cookie的值。

  • expire :Cookie的过期时间,可以是一个Unix时间戳(例如: time() + 3600 表示一小时后过期),或者是一个具体的日期时间字符串(例如: "2024-01-01 00:00:00" )。

  • path :可选参数,指定Cookie的有效路径。默认为当前路径。

  • domain :可选参数,指定Cookie的有效域名。默认为空,表示当前域名。

  • secure :可选参数,指定是否仅通过安全的HTTPS连接传输Cookie。默认为 false 。

  • httponly:可选参数,指定是否仅通过HTTP协议访问Cookie。默认为 false 。

$expire=time()+60*60*24*7;
setcookie("username", "maoshu", $expire);
setcookie("userid", "1", $expire);
​
setcookie("user[name]", "maoshu", $expire);
setcookie("user[phone]", "18611112222", $expire);
setcookie("user[age]", "35", $expire);
获取cookie
// 输出 cookie 值
if(isset($_COOKIE["username"])){
    echo $_COOKIE["username"];
}   
​
// 查看所有 cookie
print_r($_COOKIE);
​
删除 Cookie
setcookie("username", "", time()-3600);

session

  • 用于在服务器上存储关于用户会话(session)的信息,并且对于程序中的所有页面都是可用的。

  • 会话信息是临时的,在用户离开网站后将被删除。

  • 它允许在同一个用户的多个请求之间保持数据的状态,便于传递数据。 Session 的工作机制是:为每个访客创建一个唯一的 id (UID),并基于这个 UID 来存储变量。UID 存储在 cookie 中,或者通过 URL 进行传导。

启动session

通常,将该函数放在PHP文件的顶部

session_start();
存取 Session 变量

一旦Session启动,可以使用 $_SESSION 超全局变量来存储和访问Session数据。

// 存储 session 数据 
$_SESSION['username']='maoshu';
​
//取值
echo $_SESSION['username'];
​
if(isset($_SESSION['views']))
{
    $_SESSION['views']=$_SESSION['views']+1;
}
else
{
    $_SESSION['views']=1;
}
echo "浏览量:". $_SESSION['views'];
销毁 Session
if(isset($_SESSION['views']))
{
    unset($_SESSION['views']);
}
​
//销毁
session_destroy();

注意:session_destroy() 将重置 session,您将失去所有已存储的 session 数据

Session和Cookie的关系和区别

关系:

  • Session和Cookie都是用于在不同请求之间保持数据的状态。

  • Session使用Cookie来跟踪和标识用户,通过在Cookie中存储Session ID来关联服务器端的Session数据。

区别:

  • 存储位置:Cookie数据存储在客户端的浏览器中,而Session数据存储在服务器端。

  • 容量限制:Cookie的容量限制通常较小,一般为几KB,而Session的容量限制较大,通常取决于服务器的配置。

  • 安全性:由于Cookie存储在客户端,可能会被篡改或窃取,因此存储敏感信息的安全性较低。相比之下,Session数据存储在服务器端,相对更安全。

  • 生命周期:Cookie可以设置过期时间,可以在浏览器关闭后仍然保持,具有较长的生命周期。而Session通常在用户关闭浏览器或一段时间不活动后自动过期。

  • 存储方式:Cookie以键值对的形式存储数据,可以在客户端进行读取和修改。Session数据存储在服务器端,客户端只保存了一个Session ID。

在实际应用中,Cookie通常用于存储一些较小、不敏感的数据,如用户首选项、购物车信息等。而Session通常用于存储用户的身份验证信息、敏感数据等,因为Session数据存储在服务器端,相对更安全。

实战案例:个人中心

案例介绍: 我们会用最基础的原生 php 方式去做这个项目,不用任何前后端框架,考虑到一些学员没有前端基础,所以我会尽量少的使用 js,但会用到 fetch 请求等基础语句,并且 html 和 css 会有入门级的讲解(简单); 我会尽可能多的使用学到的知识,以达到学以致用的效果; 我们会使用面向对象去对一些常用的方法进行封装,例如数据库操作,让大家学会在实际项目中使用类和对象。

讲解的内容:

  • 什么是前端,什么是后端;什么是前台,什么是后台

  • 页面搭建 (从 0 到 1)

  • 什么是 json

  • 简单的 Api 接口和请求

  • Php 调试代码

  • 封装类

  • 文件包含

  • 数据库的使用

  • 用户状态

![[Pasted image 20231116090904.png]]

用户注册

用户登录

用户中心

个人信息
登录记录
修改密码
退出登录

实战补充知识

str_repeat()rtrim () ltrim() 函数

floor()ceil() round() 函数

md5() 加密

die 和 exit 函数

常量 DIRECTORY_SEPARATOR

Pdo 补充知识

$stmt->closeCursor() If($condition instanceof Closure)

dirname ()

dirname 函数用于返回指定路径的目录部分。它接受一个字符串参数,该参数是一个文件或目录的路径,并返回该路径的父级目录。

$path = '/var/www/html/index.php';
$directory = dirname($path);
echo $directory;  // 输出: /var/www/html
​
$path = '/var/www/html/';
$directory = dirname($path);
echo $directory;  // 输出: /var/www
​
$path = '/var/www/html';
$directory = dirname($path);
echo $directory;  // 输出: /var/www

header ()函数

header() 函数用于发送原始的 HTTP 头信息。它通常用于在服务器响应中设置 HTTP 头,例如设置重定向、设置响应状态码、设置内容类型等。

header(string $header, bool $replace = true, int $http_response_code = null): void

参数说明:

  • $header :要设置的 HTTP 头信息,以字符串形式表示。

  • $replace (可选):指定是否替换之前设置的相同类型的 HTTP 头信息。默认为 true ,表示替换。

  • $http_response_code(可选):指定要设置的响应状态码。

//重定向
header("Location: ./login.php");
//设置响应状态码:
header("HTTP/1.1 404 Not Found");
//设置内容类型
header("Content-Type: application/json");

注意: header() 函数必须在发送任何实际输出之前调用,包括 HTML 标记、空格、换行符等。如果在输出之后调用 header() 函数,将会导致 "headers already sent" 错误。

静态变量的使用

与类或函数相关联,而不是与对象或函数的实例相关联。 静态变量在整个脚本的执行过程中保持其值不变。

class MyClass {
    public static $count = 0;
    public static function toObj()
    {
      return new self;
    }
    public function plusCount() {
        self::$count++;
        echo self::$count.PHP_EOL;
    }
}
MyClass::toObj()->plusCount();
MyClass::toObj()->plusCount();
MyClass::toObj()->plusCount();
echo MyClass::$count;
普通函数

静态变量只在函数的作用域内有效,不同函数中的同名静态变量是相互独立的

function myFunction() {
    static $count = 0;
    
    $count++;
    echo $count.PHP_EOL;
}
​
function mySecond() {
    static $count = 0;
    echo $count.PHP_EOL;
}
myFunction();
myFunction();
myFunction();
​
mySecond();

学习自b占maoshu

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值