Skip to content

PHP var_dump() 函数返回变量的数据类型和值

echo PHP_EOL; 换行符 兼容更大平台

虽然 PHP 是弱类型语言,但也需要明白变量类型及它们的意义,因为我们经常需要对 PHP 变量进行比较,包含松散和严格比较。

  • 松散比较:使用两个等号 == 比较,只比较值,不比较类型。
  • 严格比较:用三个等号 === 比较,除了比较值,也比较类型。

例如,"42" 是一个字符串而 42 是一个整数。FALSE 是一个布尔值而 "false" 是一个字符串。

设置 PHP 常量

设置常量,使用 define() 函数,函数语法如下:

php
bool define ( string $name , mixed $value [, bool $case_insensitive = false ] )

该函数有三个参数:

  • name:必选参数,常量名称,即标志符。
  • value:必选参数,常量的值。
  • case_insensitive :可选参数,如果设置为 TRUE,该常量则大小写不敏感。默认是大小写敏感的。

常量定义在函数外也可以正常使用常量。

使用常量时,不能在常量名前添加$ 符号,不然会将常量转换成新的未定义变量使用,会导致报错。

并置运算符 (.) 用于把两个字符串值连接起来。

PHP strlen() 函数

有时知道字符串值的长度是很有用的。

strlen() 函数返回字符串的长度(字节数)。

echo strlen("Hello world!");

PHP strpos() 函数

strpos() 函数用于在字符串内查找一个字符或一段指定的文本。

如果在字符串中找到匹配,该函数会返回第一个匹配的字符位置。如果未找到匹配,则返回 FALSE。

php
echo strpos("Hello world!","world");

上面的代码将输出:6

提示:在上面的实例中,字符串 "world" 的位置是 6。之所以是 6 而不是 7 的原因是,字符串中第一个字符的位置是 0,而不是 1。

PHP 逻辑运算符

x xor y异或如果 x 和 y 有且仅有一个为 true,则返回 truex=6 y=3 (x==6 xor y==3) 返回 false
! x如果 x 不为 true,则返回 truex=6 y=3 !(x==y) 返回 true

三元运算符

(expr1) ? (expr2) : (expr3)

PHP7+ 版本多了一个 NULL 合并运算符 ??

(expr1) ?? (expr2)

组合比较符(PHP7+)

PHP7+ 支持组合比较符(combined comparison operator)也称之为太空船操作符,符号为 <=>。组合比较运算符可以轻松实现两个变量的比较,当然不仅限于数值类数据的比较。

语法格式如下:

php
$c = $a <=> $b;

解析如下:

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

获取数组的长度 - count() 函数

count() 函数用于返回数组的长度(元素的数量):

实例

php
$cars=array("Volvo","BMW","Toyota"); 
echo count($cars);

PHP 关联数组

关联数组是使用您分配给数组的指定的键的数组。

这里有两种创建关联数组的方法:

$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");

or:

php
$age['Peter']="35";
$age['Ben']="37";
$age['Joe']="43";

随后可以在脚本中使用指定的键:

实例

php
$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");
echo "Peter is " . $age['Peter'] . " years old.";

遍历关联数组

遍历并打印关联数组中的所有值,您可以使用 foreach 循环,如下所示:

实例

php
$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");
foreach($age as $x=>$x_value) { 
    echo "Key=" . $x . ", Value=" . $x_value;    echo "<br>"; 
}

PHP - 数组排序函数

在本章中,我们将一一介绍下列 PHP 数组排序函数:

  • sort() - 对数组进行升序排列

  • rsort() - 对数组进行降序排列

  • asort() - 根据关联数组的值,对数组进行升序排列

  • ksort() - 根据关联数组的键,对数组进行升序排列

  • arsort() - 根据关联数组的值,对数组进行降序排列

  • krsort() - 根据关联数组的键,对数组进行降序排列

  • sort($cars);

array_keys() 函数返回包含数组中所有键名的一个新数组,如果提供了第二个参数,则只返回键值为该值的键名。

PHP $GLOBALS

$GLOBALS 是PHP的一个超级全局变量组,在一个PHP脚本的全部作用域中都可以访问。

$GLOBALS 是一个包含了全部变量的全局组合数组。变量的名字就是数组的键。

$GLOBALS['z'] = $GLOBALS['x'] + $GLOBALS['y'];

PHP $_GET

PHP $_GET 同样被广泛应用于收集表单数据,在HTML form标签的指定该属性:"method="get"。

$_GET 也可以收集URL中发送的数据。

假定我们有一个包含参数的超链接HTML页面:

html
<html>
<body>

<a href="test_get.php?subject=PHP&web=runoob.com">Test $GET</a>

</body>
</html>

当用户点击链接 "Test $GET", 参数 "subject" 和 "web" 将发送至"test_get.php",你可以在 "test_get.php" 文件中使用 $_GET 变量来获取这些数据。

构造方法

public就是公有

private就是私有

protected受保护的

php
public function  __contruct()

{

}

new 来创建实例

构造方法就是对象运行时首先运行的

析构方法

php
public function  __destruct()

{

}

与构造方法相反

在对象被销毁最后再运行的

也可以先调用 用unset();

类里面定义常量用const

属于对象的属性和方法用$this

调用类的属性和方法用self::

在外面调用类的直接用类的名字,然后两个冒号::调用里面的属性和方法

类的继承

class Boy extends Dad{

}

用extends继承父类

父类方法是私有,子类继承不了

子类方法与父类方法同名,将覆盖

构造方法也是可以继承,也可以覆盖

像构造方法继续调用父类,用parent::__construct();

开头加上final即是不给继承,不论是父类的类加上还是里面的方法,都可以不给继承对应的

命名空间

namespace venter\session

就像把同名的文件,放在不同的文件夹

受命名空间定义常量要用const,

use benter\session\Imooc;

use直接用命名空间文件

use venter\Imooc as Imooc2;

用as建个假名,可以不重复use一样的名字

use function venter\Ilikemooc;

函数的话要带上function

use const venter\qqq;

常量用const

include引入其他php文件
include '1.php';

在命名空间里调用全局空间的类要用var_dump(new \Test1())反斜杠。

常量和函数,会自己先去命名空间找,然后全局空间找,所以直接用就行。

类自动加载

php
function __autoload($className)

{

	require $className.".php"

}

$imooc=new Imooc();

var_dump($imooc);

可以不用inculde引用,直接去找到类文件路由

更科学的

php
sql_autoload_register(function($className){

	require $className.".php"

})



class Momo

{

	function autoload($className

​	{

require $className.".php"

​	}

}

sql_autoload_register([new Momo,'autoload']);

当类里的属性或者方法前面加上了static,那就属于这个类了,而不是对象,就不需要实例化,就可以调用这个方法和属性,用类名加上两冒号再加上属性或方法来输出,如echo(Person::work());

在类里的方法加上static要yongself::在类本身获取

命名空间+类名和文件路径对应

php
spl_autoload_register(function ($className){
    include str_replace("\\","/",$className.".php");
    }
);
$imooc=new wangzhanImooc();
var_dump($imooc);

就可以很方便的取得,多用这个来命名

后期静态绑定

php
class A{
    function who(){
        echo "a";
    }
    function test(){
        **self**::who();
    }
}
class B extends A
{
    function who()
    {
        echo "b";
    }
}
B::test();

用self是没有判断,直接用什么类来调用方法,改为static就可以判断什么类调用什么方法。

修改后

php
class A{
    function who(){
        echo "a";
    }
    function test(){
        **static**::who();
    }
}
class B extends A
{
    function who()
    {
        echo "b";
    }
}
B::test();

魔术方法

__set

__get

php
class Test{
    private $abc='';
    private $lzh='';
    public  function set($val,$b){
        $this->$val=$b;
    }
    public  function get($val){
        return $this->$val;
    }
}
$test=new Test();
$test->lzh="abcd";
var_dump($test->lzh);

如果要用isset方法判断私有属性是做不到的,要在类里加一个__set方法,可以帮忙判断私有属性

php
class Test{
    private $abc="abv";
    public function __isset($name)
    {
        return isset($this->$name)?true:flase;
    }
}
$test=new Test();
var_dump(isset($test->abc));

当没找到属性时,因为被设为私有,会自动去__isset方法里找。

__isset

__unset

php
class Test{
    private $abc="abv";
    public function unset($name)
    {
        echo"已被删除";
        unset($this->$name);
    }
    public function  isset($name)
    {
        return isset($this->$name)?true:false;
    }
}
$test=new Test();
unset($test->abc);
var_dump(isset($test->abc));

当一个方法不存在给调用,用__call可以防止报错,并且用数组方式输出

php
class Test{
    public  function __call($zzz,$qqq){
        echo $zzz."<br>";
        print_r($qqq);
    }
}
$test=new Test();
$test->go(1);

当时静态方法,静态调用不存在

php
class Test{
    public static  function __callStatic($zzz,$qqq){
        echo $zzz."<br>";
        print_r($qqq);
    }
}
Test::go(1,"ok");

这是一个对象里,像方法一样的传递参数,然后通过类里的__inboke来用参数完成里面内容

php
class Test{
    public function __invoke($arg)
    {
        var_dump($arg);// TODO: Implement __invoke() method.
    }
}
$test=new Test();
$test('哈哈哈');

__tostring方法就是echo对象返回__tostring方法内容

php
class Test{
    public  function  __toString()
    {
        return "tostring方法";    }
}
$test=new Test();
echo $test;

浅拷贝与深拷贝

  • 浅拷贝就是经常用的赋值,当其中一个改了就一起改,就像一把钥匙,你和你爸爸共用,然后你磨损了,你老爸拿到的也是同一把,也磨损了。
php
class A{
    public $age=0;
}
$a=new A();
$b=$a;
$b->age=1;
var_dump($a->age);
  • 深拷贝就是复制一份出来,不是共有了,就像钥匙复刻多了一只,你的磨了,你老爸的也没啥事。

用clone就是克隆多一份

php
class A{
    public $age=0;
}
$a=new A();
$b=clone $a;
$b->age=1;
var_dump($a->age);

当克隆一个对象时,要用clone,并且被克隆的类里要有__clone方法,用 $obj复制本身出去;

php
class Car {
    public $name = 'car';
    
    public function __clone() {
        $obj = new Car();
        $obj->name = $this->name;
    }
}
$a = new Car();
$a->name = 'new car';
$b = clone $a;
var_dump($b);

当要限制方法里的传递参数必须为什么类的实例化,在传递是前面加上类的名字,传递的要是实例。

php
class A{
    public $name="";
    public function go(){
        echo "gogogogogogo.....";
    }
}

function test(**A $a**)
{
    $a->go();
}
test(**new A()**);

trait可以让别的类来复用,用use来用,trait可以嵌套

php
trait A{
    public $abc='ssss';
    public function a(){
        echo "加";
    }
}
trait B{
    public function b(){
    echo "油";
}
trait D{
    use A,B;
}
class C{
    use D;
    public function zzz(){
        echo $this->abc;
    }
}



$c=new C();
$c->a();
$c->b();
$c->zzz();

接口类

用interface定义接口,创建类用implements来连接接口,接口所需方法必须实现。在类里方法传道值前面加上接口名,传导的是用了接口的类的实例化对象,然后就可以了。

php
interface Person{
    public function eat();
    public function sleep();
}
class Man implements Person{
    public  function eat(){
        echo"吃汉堡包啦";
        echo PHP_EOL;
    }
    public  function sleep(){
        echo"记得早点休息";
    }
}
class Woman implements Person{
    public  function eat(){
        echo"吃减肥水果";
        echo PHP_EOL;
    }
    public  function sleep(){
        echo"超级早休息";
    }
}
class L{
    public static function factory(Person $user)
    {
        return $user;
    }
}
$user=L::factory(new Woman());
$user->eat();
$user->sleep();

抽象类

php
abstract class a{
    public function time(){
        echo "周末的时候";
    }
    public function eat(){}
    public function sleep(){}
}
class c extends a{
    public function eat()
    {
        echo "吃啥呢";
    }
    public function sleep()
    {
        $this->time();
        echo "睡懒觉啦";
    }
}
$c=new c();
$c->eat();
$c->sleep();

单例模式

需要实例化多次的时候使用单例模式可以减少内存

php
class Test{
    private  static  $zzz=null;
    private  function __construct()
    {
    }
    private  function  __clone()
    {
        // TODO: Implement __clone() method.
    }
    public static  function  gethhh(){
        if(!(self::$zzz instanceof  self)){
            self::$zzz=new self();
        }
        return self::$zzz;
    }
}

$test1=Test::gethhh();
$test2=Test::gethhh();
$test3=Test::gethhh();
$test4=Test::gethhh();

var_dump($test1);
var_dump($test2);
var_dump($test3);
var_dump($test4);

工厂模式

当一个类要实例化非常多,很多很乱,当一个类要改,要一个个找到去改,很麻烦,用工厂模式就是用一个类里的静态方法来返回一个经常用的类的实例化,需要改的时候,改静态方法里的内容就行

php
class Memcache{
    public  function set($k,$v)
    {
    }
    public  function get($k)
    {

    }
    public  function delete($k)
    {

    }
}

class Cache{
    public  static  function  factory(){
        return new Memcache();
    }
}

$hhh=Cache::factory();
$hhh->set();

$_GET、$_POST 和 $_REQUEST 的区别?

$_GET 变量接受所有以 get 方式发送的请求,及浏览器地址栏中的 ? 之后的内容。

$_POST 变量接受所有以 post 方式发送的请求,例如,一个 form 以 method=post 提交,提交后 php 会处理 post 过来的全部变量。

$_REQUEST 支持两种方式发送过来的请求,即 postget 它都可以接受,显示不显示要看传递方法,get 会显示在 url 中(有字符数限制),post 不会在 url 中显示,可以传递任意多的数据(只要服务器支持)。

GETPOST
后退按钮/刷新无害数据会被重新提交(浏览器应该告知用户数据会被重新提交)。
书签可收藏为书签不可收藏为书签
缓存能被缓存不能缓存
编码类型application/x-www-form-urlencodedapplication/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。
历史参数保留在浏览器历史中。参数不会保存在浏览器历史中。
对数据长度的限制是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。无限制。
对数据类型的限制只允许 ASCII 字符。没有限制。也允许二进制数据。
安全性与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET !POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。
可见性数据在 URL 中对所有人都是可见的。数据不会显示在 URL 中。
php
$_SERVER["REQUEST_METHOD"] == "POST"

判断提交的数据是否是POST方式传来的

php
empty($_POST["name"])

empty() 函数用于检查一个变量是否为空。

如何避免 $_SERVER["PHP_SELF"] 被利用?

$_SERVER["PHP_SELF"] 可以通过 htmlspecialchars() 函数来避免被利用。

php
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

htmlspecialchars() 把一些预定义的字符转换为 HTML 实体。现在如果用户想利用 PHP_SELF 变量, 结果将输出如下所示:

php
<form method="post" action="test_form.php/&quot;&gt;&lt;script&gt;alert('hacked')&lt;/script&gt;">

尝试该漏洞失败!

preg_match() 函数可以根据正则表达式对字符串进行搜索匹配

php
!preg_match("/^[a-zA-Z ]*$/",$name

当用户提交表单时,我们将做以下两件事情,:

  1. 使用 PHP trim() 函数去除用户输入数据中不必要的字符 (如:空格,tab,换行)。
  2. 使用PHP stripslashes()函数去除用户输入数据中的反斜杠 ()。
  3. htmlspecialchars() 把一些预定义的字符转换为 HTML 实体。

接下来让我们将这些过滤的函数写在一个我们自己定义的函数中,这样可以大大提高代码的复用性。还可以提交失败时保留所写信息

php
function test_input($data){
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;
}

test_input()是一个自定的函数,过滤提交信息,防止被攻击。

$name = test_input($_POST["name"]);

function getsum(...$num){}

三个省略号代表可变参数,就是想传多少参数到$num都行

引用传递

function getsum(&$a,&$b){}

不用返回值,实参和形参都是一起的,改了一起改

在函数内使用全局变量

$GLOBALS["a"] 或者global $a

前者会影响外面的变量,后者不会

递归函数

php
$sum=$a+xxx($a-1);

匿名函数

php
<?php$qqq="message";    $zzz=function ()use($qqq){        echo $qqq;    };    $zzz();

匿名函数要使用外面变量要用use($a)在function()后面

php
<?php$qqq="message";    $zzz=function ()use(&$qqq){        echo $qqq;    };$qqq="ghhh";    $zzz();

外面变量如果在函数后面变动要显示,要给用use(&$a)

匿名函数也可以传参

php
<?php    function aaa($name,Closure $clo){        echo "你好{$name}\n";        $clo();    }    aaa("林泽豪",function ()    {        echo "欢迎";    });

可以设置形参为闭包函数,Closure $clo来设置一个闭包形参,在函数里直接调用$clo(),就是外面实参为闭包函数的方法。

可变函数,就是把函数名设的有共同的,在另一个方法里让用户输入区别的地方,这样就可以用一种方法调用不同方法,就无需用户输入什么就if_else来判断,如果水果种类有几百种,那就要判断几百次,这个可以灵活解决

php
function get_apple($num){
   echo "你是要苹果".$num."箱";
}
function get_banana($num){
    echo "你是要香蕉".$num."箱";
}
function get_fruit($fruit,$num){
       $a="get_".$fruit;
       $a($num);
}
get_fruit("banana",8);

代码复用

单独引入:

include和require

前者不会中断代码运行,只会抛出一个错误。

后者会出现致命错误,中断代码运行/

include_once和require_once

不加_once,如果重复调用会报错,加了重复用就不会

路径引入:

​ set_include_path

​ get_include_path

平时引入路径,会重复路径

include("testa/test1.php");

include("testa/test2.php");

先确定一个文件夹

set_include_path(''testa'');

include("test1.php");

include("test2.php");

set_include_path(get_include_path.PATH_SEPARATOR.''testa'');

set_include_path(get_include_path.PATH_SEPARATOR.''testb'');

PATH_SEPARATOR=路径分节符

set_include_path(get_include_path.PATH_SEPARATOR.''testa'');

=====

ini_set('include_path',get_include_path.PATH_SEPARATOR.''testa'');

restore_include_path();取消引入

设置时区

php
date_default_timezone_set('PRC');

获取时区

php
echo ("当前时区为:".date_default_timezone_get().'<br>');

动态设置,每一个页面都要设置

date()函数

获取时间

Y--年

m--月

d--日

H--小时

i--分钟

s--秒

空格a--am

空格A--AM

g--十二小时制小时

w--星期几,0-6,0为星期日

L--判断是否为闰年,真为是,反之不是

W--当年的第几周

z--当年的第几天

t--这个月有几天

php
echo date('Y年m月d日').'<br>';

时间戳

从1970年1月1日开始到现在的时间,秒数

用time()

mktime()

返回哪一天的时间戳

用strtotime()可以从哪个时间开始之后一段时间的时间

echo date("Y-m-d H:i:s",strtotime('+5 years +3 months +12 days'))."<br/>";

strtotime('+5 years +3 months +12 days')).microtime()获取微秒和时间戳。

echo microtime(true)就是获取将微秒和时间戳合并

算程序运行时间

php

$start=microtime(true);
for($i=1;$i<=1000000;$i++)
{
    $arr[]=$i;
}
$end=microtime(true);
echo"程序运行".round($end-$start,4)."秒";

checkdate()验证日期合法性

getdate()获取很多日期信息

gettimeofday()获取秒和微秒

PHP类和对象之类的属性

访问控制的关键字代表的意义为:

public:公开的 protected:受保护的 private:私有的

php
class Car {
    //定义公共属性
    public $name = '汽车';

    //定义受保护的属性
    protected $corlor = '白色';

    //定义私有属性
    private $price = '100000';
}

默认都为public,外部可以访问。一般通过->对象操作符来访问对象的属性或者方法,对于静态属性则使用::双冒号进行访问。当在类成员方法内部调用的时候,可以使用$this伪变量调用当前对象的属性。

PHP类和对象之Static静态关键字

静态属性与方法可以在不实例化类的情况下调用,直接使用类名::方法名的方式进行调用。静态属性不允许对象使用->操作符调用。

静态方法中,$this伪变量不允许使用。可以使用self,parent,static在内部调用静态方法与属性。

PHP类和对象之重载

方法的重载通过__call来实现,当调用不存在的方法的时候,将会转为参数调用__call方法,当调用不存在的静态方法时会使用__callStatic重载。

php
public function __call($name,$args){
        if($name=='speedDown'){
            $this->speed-=10;
        }
    }
}

对象序列化

对象序列化,可以通过serialize方法将对象序列化为字符串,用于存储或者传递数据,然后在需要的时候通过unserialize将字符串反序列化成对象进行使用。

php
class Car {
    public $name = 'car';
}
$a = new Car();
$str = serialize($a); //对象序列化成字符串
echo $str.'<br>';
$b = unserialize($str); //反序列化为对象
var_dump($b);

正则表达式

preg_match用于执行一个正则匹配,常用来判断一类字符模式是否存在。

php
$p = '/苹果/';

$str = "我喜欢吃苹果";
if (preg_match($p, $str)) {
    echo '匹配成功';
}

CRE库函数中,正则匹配模式使用分隔符与元字符组成,分隔符可以是非数字、非反斜线、非空格的任意字符。经常使用的分隔符是正斜线(/)、hash符号(#) 以及取反符号(~),例如:

php
/foo bar/
#^[^0-9]$#
~php~

如果模式中包含分隔符,则分隔符需要使用反斜杠(\)进行转义。

php
/http:\/\//

如果模式中包含较多的分割字符,建议更换其他的字符作为分隔符,也可以采用preg_quote进行转义。

分隔符后面可以使用模式修饰符,模式修饰符包括:i, m, s, x等,例如使用i修饰符可以忽略大小写匹配:

php
$str = "Http://www.imooc.com/";
if (preg_match('/http/i', $str)) {
    echo '匹配成功';
}
php
//下面的\s匹配任意的空白符,包括空格,制表符,换行符。[^\s]代表非空白符。[^\s]+表示一次或多次匹配非空白符。
$p = '/^我[^\s]+(苹果|香蕉)$/';
$str = "我喜欢吃苹果";
if (preg_match($p, $str)) {
    echo '匹配成功';
}

查找所有匹配结果

preg_match只能匹配一次结果,但很多时候我们需要匹配所有的结果,preg_match_all可以循环获取一个列表的匹配结果数组。

php
preg_replace     验证与替换
php
preg_replace($patterns, $replace, '{startDate} = 1999-5-27');
php
$patterns = array ('/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/',
                   '/^\s*{(\w+)}\s*=/');
$replace = array ('\3/\4/\1\2', '$\1 =');//\3等效于$3,\4等效于$4,依次类推

用正则替换来去掉多余的空格与字符:

php
$str = 'one     two';
$str = preg_replace('/\s+/', ' ', $str);
echo $str; // 结果改变为'one two'

设置cookie

PHP设置Cookie最常用的方法就是使用setcookie函数,setcookie具有7个可选参数,我们常用到的为前5个:

name( Cookie名)可以通过$_COOKIE['name'] 进行访问 value(Cookie的值) expire(过期时间)Unix时间戳格式,默认为0,表示浏览器关闭即失效 path(有效路径)如果路径设置为'/',则整个网站都有效 domain(有效域)默认整个域名都有效,如果设置了'www.imooc.com',则只在www子域中有效

php
setcookie("TestCookie", $value, time()+3600, "/path/", "imooc.com"); //设置路径与域

cookie的删除与过期时间

通过前面的章节,我们了解了设置cookie的函数,但是我们却发现php中没有删除Cookie的函数,在PHP中删除cookie也是采用setcookie函数来实现。

php
setcookie('test', '', time()-1);

cookie的有效路径

cookie中的路径用来控制设置的cookie在哪个路径下有效,默认为'/',在所有路径下都有,当设定了其他路径之后,则只在设定的路径以及子路径下有效,例如:

php
setcookie('test', time(), 0, '/path');

session与cookie的异同

cookie将数据存储在客户端,建立起用户与服务器之间的联系,通常可以解决很多问题,但是cookie仍然具有一些局限:

cookie相对不是太安全,容易被盗用导致cookie欺骗 单个cookie的值最大只能存储4k 每次请求都要进行网络传输,占用带宽

session是将用户的会话数据存储在服务端,没有大小限制,通过一个session_id进行用户识别,PHP默认情况下session id是通过cookie来保存的,因此从某种程度上来说,seesion依赖于cookie。但这不是绝对的,session id也可以通过参数来实现,只要能将session id传递到服务端进行识别的机制都可以使用session。

php
//开始使用session
session_start();
//设置一个session
$_SESSION['test'] = time();
//显示当前的session_id
echo "session_id:".session_id();
echo "<br>";
//读取session值
echo $_SESSION['test'];

//销毁一个session
unset($_SESSION['test']);
echo "<br>";
var_dump($_SESSION);

如果要删除所有的session,可以使用session_destroy函数销毁当前session,session_destroy会删除所有数据,但是session_id仍然存在。

php
session_start();
$_SESSION['name'] = 'jobs';
$_SESSION['time'] = time();
session_destroy();

值得注意的是,session_destroy并不会立即的销毁全局变量$_SESSION中的值,只有当下次再访问的时候,$_SESSION才为空,因此如果需要立即销毁$_SESSION,可以使用unset函数。

php
session_start();
$_SESSION['name'] = 'jobs';
$_SESSION['time'] = time();
unset($_SESSION);
session_destroy(); 
var_dump($_SESSION); //此时已为空

如果需要同时销毁cookie中的session_id,通常在用户退出的时候可能会用到,则还需要显式的调用setcookie方法删除session_id的cookie值。

使用session来存储用户的登录信息

session可以用来存储多种类型的数据,因此具有很多的用途,常用来存储用户的登录信息,购物车数据,或者一些临时使用的暂存数据等。

用户在登录成功以后,通常可以将用户的信息存储在session中,一般的会单独的将一些重要的字段单独存储,然后所有的用户信息独立存储。

php
$_SESSION['uid'] = $userinfo['uid'];
$_SESSION['userinfo'] = $userinfo;

一般来说,登录信息既可以存储在sessioin中,也可以存储在cookie中,他们之间的差别在于session可以方便的存取多种数据类型,而cookie只支持字符串类型,同时对于一些安全性比较高的数据,cookie需要进行格式化与加密存储,而session存储在服务端则安全性较高。

php
session_start();
//假设用户登录成功获得了以下用户数据
$userinfo = array(
    'uid'  => 10000,
    'name' => 'spark',
    'email' => 'spark@imooc.com',
    'sex'  => 'man',
    'age'  => '18'
);
header("content-type:text/html; charset=utf-8");
/* 将用户信息保存到session中 */
$_SESSION['uid'] = $userinfo['uid'];
$_SESSION['name'] = $userinfo['name'];
$_SESSION['userinfo'] = $userinfo;

//* 将用户数据保存到cookie中的一个简单方法 */
$secureKey = 'imooc'; //加密密钥
$str = serialize($userinfo); //将用户信息序列化
//用户信息加密前
$str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($secureKey), $str, MCRYPT_MODE_ECB));
//用户信息加密后
//将加密后的用户数据存储到cookie中
setcookie('userinfo', $str);

//当需要使用时进行解密
$str = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($secureKey), base64_decode($str), MCRYPT_MODE_ECB);
$uinfo = unserialize($str);
echo "解密后的用户信息:<br>";
print_r($uinfo);

PHP文件系统之读取文件内容

PHP具有丰富的文件操作函数,最简单的读取文件的函数为file_get_contents,可以将整个文件全部读取到一个字符串中。

php
$content = file_get_contents('./test.txt');

file_get_contents也可以通过参数控制读取内容的开始点以及长度。

php
$content = file_get_contents('./test.txt', null, null, 100, 500);

PHP也提供类似于C语言操作文件的方法,使用fopen,fgets,fread等方法,fgets可以从文件指针中读取一行,freads可以读取指定长度的字符串。

php
$fp = fopen('./text.txt', 'rb');
while(!feof($fp)) {
    echo fgets($fp); //读取一行
}
fclose($fp);
php
$fp = fopen('./text.txt', 'rb');
$contents = '';
while(!feof($fp)) {
    $contents .= fread($fp, 4096); //一次读取4096个字符
}
fclose($fp);

使用fopen打开的文件,最好使用fclose关闭文件指针,以避免文件句柄被占用。

PHP文件系统之判断文件是否存在

一般情况下在对文件进行操作的时候需要先判断文件是否存在,PHP中常用来判断文件存在的函数有两个is_file与file_exists.

php
$filename = './test.txt';
if (file_exists($filename)) {
    echo file_get_contents($filename);
}

如果只是判断文件存在,使用file_exists就行,file_exists不仅可以判断文件是否存在,同时也可以判断目录是否存在,从函数名可以看出,is_file是确切的判断给定的路径是否是一个文件。

更加精确的可以使用is_readable与is_writeable在文件是否存在的基础上,判断文件是否可读与可写。

php
$filename = './test.txt';
if (is_writeable($filename)) {
    file_put_contents($filename, 'test');
}
if (is_readable($filename)) {
    echo file_get_contents($filename);
}

超级简单的小问题

$filename = './test.txt' 那个点是干啥的 前面有讲吗 我都忘了 /捂脸

./ 当前目录 ../ 父级目录 / 根目录

PHP文件系统之取得文件的修改时间

文件有很多元属性,包括:文件的所有者、创建时间、修改时间、最后的访问时间等。

php
fileowner:获得文件的所有者
filectime:获取文件的创建时间
filemtime:获取文件的修改时间
fileatime:获取文件的访问时间

其中最常用的是文件的修改时间,通过文件的修改时间,可以判断文件的时效性,经常用在静态文件或者缓存数据的更新。

php
$mtime = filemtime($filename);
echo '修改时间:'.date('Y-m-d H:i:s', filemtime($filename));
php
$filename = '/data/webroot/usercode/code/resource/test.txt';
echo '所有者:'.fileowner($filename).'<br>';
echo '创建时间:'.filectime($filename).'<br>';
echo '修改时间:'.filemtime($filename).'<br>';
echo '最后访问时间:'.fileatime($filename).'<br>';

//给$mtime赋值为文件的修改时间
$mtime = filemtime($filename); 
//通过计算时间差 来判断文件内容是否有效
if (time() - $mtime > 3600) {
    echo '<br>缓存已过期';
} else {
    echo file_get_contents($filename);
}

PHP文件系统之取得文件的大小

通过filesize函数可以取得文件的大小,文件大小是以字节数表示的。

php
$filename = '/data/webroot/usercode/resource/test.txt';
$size = filesize($filename);

如果要转换文件大小的单位,可以自己定义函数来实现。

php
function getsize($size, $format = 'kb') {
    $p = 0;
    if ($format == 'kb') {
        $p = 1;
    } elseif ($format == 'mb') {
        $p = 2;
    } elseif ($format == 'gb') {
        $p = 3;
    }
    $size /= pow(1024, $p);
    return number_format($size, 3);
}

$filename = '/data/webroot/usercode/code/resource/test.txt';
$size = filesize($filename);

$size = getsize($size, 'kb'); //进行单位转换
echo $size.'kb';

PHP文件系统之写入内容到文件

与读取文件对应,PHP写文件也具有两种方式,最简单的方式是采用file_put_contents。

php
$filename = './test.txt';
$data = 'test';
file_put_contents($filename, $data);

上例中,$data参数可以是一个一维数组,当$data是数组的时候,会自动的将数组连接起来,相当于$data=implode('', $data);

PHP文件系统之删除文件

跟Unix系统命令类似,PHP使用unlink函数进行文件删除。

php
unlink($filename);

删除文件夹使用rmdir函数,文件夹必须为空,如果不为空或者没有权限则会提示失败。

php
rmdir($dir);

如果文件夹中存在文件,可以先循环删除目录中的所有文件,然后再删除该目录,循环删除可以使用glob函数遍历所有文件。

php
foreach (glob("*") as $filename) {
   unlink($filename);
}

PHP异常处理之抛出一个异常

1、基本语法

```php

try{ //可能出现错误或异常的代码 //catch表示捕获,Exception是php已定义好的异常类 } catch(Exception $e){ //对异常处理,方法: //1、自己处理 //2、不处理,将其再次抛出 } ```

2、处理处理程序应当包括: Try - 使用异常的函数应该位于 "try" 代码块内。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常。 Throw - 这里规定如何触发异常。注意:每一个 "throw" 必须对应至少一个 "catch",当然可以对应多个"catch" Catch - "catch" 代码块会捕获异常,并创建一个包含异常信息的对象。

php
//创建可抛出一个异常的函数
function checkNum($number){
     if($number>1){
         throw new Exception("异常提示-数字必须小于等于1");
     }
     return true;
 }
 
//在 "try" 代码块中触发异常
 try{
     checkNum(2);
     //如果异常被抛出,那么下面一行代码将不会被输出
     echo '如果能看到这个提示,说明你的数字小于等于1';
 }catch(Exception $e){
     //捕获异常
     echo '捕获异常: ' .$e->getMessage();
 }

上面代码将获得类似这样一个错误:

捕获异常:: 异常提示-数字必须小于等于1

例子解释:

上面的代码抛出了一个异常,并捕获了它:

创建 checkNum() 函数。它检测数字是否大于 1。如果是,则抛出一个异常。 在 "try" 代码块中调用 checkNum() 函数。 checkNum() 函数中的异常被抛出 "catch" 代码块接收到该异常,并创建一个包含异常信息的对象 ($e)。 通过从这个 exception 对象调用 $e->getMessage(),输出来自该异常的错误消息

PHP异常处理之异常处理类

PHP具有很多异常处理类,其中Exception是所有异常处理的基类。

Exception具有几个基本属性与方法,其中包括了:

message 异常消息内容 code 异常代码 file 抛出异常的文件名 line 抛出异常在该文件的行数

其中常用的方法有:

getTrace 获取异常追踪信息 getTraceAsString 获取异常追踪信息的字符串 getMessage 获取出错信息

如果必要的话,可以通过继承Exception类来建立自定义的异常处理类。

php
//自定义的异常类,继承了PHP的异常基类Exception
class MyException extends Exception {
    function getInfo() {
        return '自定义错误信息';
    }
}

try {
    //使用异常的函数应该位于 "try"  代码块内。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常。
    throw new MyException('error');//这里规定如何触发异常。注意:每一个 "throw" 必须对应至少一个 "catch",当然可以对应多个"catch"
} catch(Exception $e) {//"catch" 代码块会捕获异常,并创建一个包含异常信息的对象
    echo $e->getInfo();//获取自定义的异常信息
    echo $e->getMessage();//获取继承自基类的getMessage信息
}

PHP异常处理之捕获异常信息

在了解了异常处理的基本原理之后,我们可以通过try catch来捕获异常,我们将执行的代码放在try代码块中,一旦其中的代码抛出异常,就能在catch中捕获。

这里我们只是通过案例来了解try catch的机制以及异常捕获的方法,在实际应用中,不会轻易的抛出异常,只有在极端情况或者非常重要的情况下,才会抛出异常,抛出异常,可以保障程序的正确性与安全,避免导致不可预知的bug。

一般的异常处理流程代码为:

php
try {
    throw new Exception('wrong');
} catch(Exception $ex) {
    echo 'Error:'.$ex->getMessage().'<br>';
    echo $ex->getTraceAsString().'<br>';
}
echo '异常处理后,继续执行其他代码';

PHP异常处理之获取错误发生的所在行

在异常被捕获之后,我们可以通过异常处理对象获取其中的异常信息,前面我们已经了解捕获方式,以及获取基本的错误信息。

在实际应用中,我们通常会获取足够多的异常信息,然后写入到错误日志中。

通过我们需要将报错的文件名、行号、错误信息、异常追踪信息等记录到日志中,以便调试与修复问题。

php
try {
    throw new Exception('报错了');
} catch(Exception $ex) {
    $msg = 'Error:'.$ex->getMessage()."\n";
    $msg.= $ex->getTraceAsString()."\n";
    $msg.= '异常行号:'.$ex->getLine()."\n";
    $msg.= '所在文件:'.$ex->getFile()."\n";
    //将异常信息记录到日志中
 file_put_contents('error.log', $msg);
 echo file_get_contents($msg);
}