Bootstrap

PHP学习笔记

非科班的苦逼程序员,深感找工作的艰辛,而且还是PHP的技术栈,找工作更加痛苦。
现把自己积累的手写php笔记,搬到CSDN上吧

1. PHP的数据类型

布尔型(Boolean)、整形(Int)、浮点型(Float)、字符串(String)、数组(Array)、对象(Object)
特殊类型:资源类型(Resource)、空类型(Null)

2. 数据类型

  • var_dump()
  • is_*()
    is_bool():是否是整形 is_int()、is_float()、is_string()、is_array()、……
    is_a(object,classname):判断对象是否为某类的对象
  • isset():判断变量是否存在/设置
    isset($a)?1:isset($b)?2:3;无论几层嵌套,都要看成前面归一类(isset($a)?1:isset($b))?2:3;
  • empty():判断变量是否为空
  • 强制转换数据类型
    (int)$name、(float)$name、(string)$name、(bool)$name、settype/gettype
    intval()、strval()
settype($name,'目标类型');//设置对应数据类型
gettype($name);			 //获取对应数据的数据类型
  • 进制转换
    bin:2进制 oct:8进制 dec:10进制 hex:16进制
$dec = 123;	 //十进制
$oct = 0123; //八进制
$hex = 0x123;//十六进制
decbin($num);//十进制转二进制
decoct($num);//十进制转八进制
dechex($num);//十进制转十六进制
bindec($num);//二进制转十进制
octdec($num);//八进制转十进制
hexdec($num);//十六进制转十进制
//base_convert(number,frombase,tobase);
//可以将number从frombase转义到任意tobase进制的数字
echo base_convert($hex,16,8); 
  • 浮点数

tip:浮点数不应该直接进行大小比较,因为所有的数字最终都是转换为二进制形式,不能完全表达准确,最终只能“以很高的精度接近理论值”,因此浮点数是不可靠的

$a = 0.1;
$b = 0.9;
$c = 1;
var_dump(($a+$b)==$c);//true   1.000000000000000
var_dump(($c-$b)==$a);//false  0.999999999999999

解决方法
1、尽量不用浮点数直接进行比较,进行round/ceil/floor等操作
2、用php的高精度运算函数

$a = 0.1;$b = 0.9;$c = 1;
var_dump(($c-$b)==$a);          // false
var_dump(bcsub($c, $b, 1)==$a); // true
//bcsub 将两个高精度数字相减
  • 字符串
$str1 = '';//单行文本,单引号,不会转义变量及特殊字符
$str2 = "";//单行文本,双引号,会转义变量及特殊字符
$str3 = <<<yyfs
heredoc
多行文本,默认双引号,也可以加上双引号,会转义变量及特殊字符
yyfs;
$str4 = <<<'yyfs'
nowdoc
多行文本,默认双引号,也可以加上双引号,不会转义变量及特殊字符
yyfs;
  • 类型自动转换
$v1 = '1def'+'2abc';//3
$v2 = 'def1'+'abc2';//0
  • 比较规律
    布尔值: ture>false
    字符串:可转为文字进行比较
"abc">true;		//false
"abc">false;	//true
"ab">"c";		//false
"3abc">"12abc"; //true
"abc">"ab123c"; //true   c>!
1>"a";			//true
"1">"a";		//false

3. 注释

单行://或#
多行:/* */

4.自增自减

布尔值:自增自减无效
null值:自减无效,自增结果为1
字符串:只能自增,效果为下一个字符,只能针对字母或者数字进行自增

$s1 = 'a';	//++  b
$s2 = 'abc';//++ abd
$s3 = 'xyzz';//xzaa
$s4 = 'zzz';//aaa
$s5 = 'abc9';//abd0

tips:循环时推荐使用++$i,因为用时比较少

5.可变变量

$s1 = 'abc';//存储字符串abc
$abc = 10;
echo $$s1;//输出10

6.预定义变量

$_GET、$_POST、$_REQUEST、$_SERVER、$_GLOBALS、$_COOKIE、$_FILES、$_SESSION、$_ENV

  • $_GET 、$_POST:获取GET或POST方法传参的数据
  • $_REQUEST:获取GET和POST方法传参的数据
  • $_SERVER:返回一些浏览器的信息
  • $_GLOBALS:存储所有全局变量
  • $_COOKIE、$_SESSION:存储COOKIE / SESSION的信息
  • $_FILES:文件上传时,存储文件信息
  • $_ENV:获取服务器端环境变量的数组

7.常量

  • define
    一般情况下:define(‘company’,‘4399’);
    但define还可以设置表达式的常量,define(‘yesterday’,246060);
    判断变量是否存在:defined() 存在返回true,不存在返回false
  • const
    const 常量名=常量值
  • 预定义常量
    M_PI:圆周率
    PHP_OS:php运行所在的操作系统
    HP_VERSION:php的版本号
    PHP_INT_MAX:php中最大的整数值
    PHP_EOL:php中的换行符
  • 魔术常量
    _ _ LINE _ _ :返回文件中的当前行号
    _ _ FILE _ _ :返回文件的完整路径和文件名
    _ _ DIR _ _ :返回该文件所在的目录
    _ _ FUNCTION _ _ :返回该函数被定义时的名字
    _ _ CLASS _ _ :返回该类被定义时的名字
    _ _ METHOD _ _ :返回类中该方法被定义时的名字
    _ _ NAMESPACE _ _ :返回当前命名空间的名字

8.流程控制替代语法

  • if(…): ……else:……endif;
  • while(……):……endwhile;
  • switch(……):case xx:……case xx:……case xx:…… endswitch;

9.匿名函数

没有名字的函数

  • 将匿名函数复制给变量
$f1 = function(){……}//定义
$f1();//调用
  • 将匿名函数作为实参使用
function func1($x,$y,$z){
	$s1 = $x + $y;
	$s2 = $x - $y;
	$z($s1,$s2);
}
//$z就是调用了一个匿名函数,将匿名函数作为参数传递
func1(3,4,function($m1.$m2){
	echo "m1=$m1,m2=$m2";
});

10.遍历数组

for和foreach比较普遍,记录一个比较特殊的,可以用while+each+list

while(list($key,$value)=each($arr)){
	echo $key,'===>',$value;
}

11.类-对象

(1)魔术方法

  • _ _constuct():在new一个对象的时候自动调用
  • _ _destruct() :当一个对象被销毁时自动调用
  • _ _call()和 _ _callStatic():当对一个对象的不存在的实例(静态)方法进行调用时自动调用
  • _ get()和 _set():对对象中不存在的属性进行“取值“和”赋值”
  • _ isset()和 _unset():对对象中不存在的属性进行isset()和unset()判断时自动调用
  • _ sleep()和 _wakeup():对象的序列化serialize和反序列化unserialize时自动调用,只能序列化其属性数据,而方法被忽略,因为方法不是数据
  • _ _toString():当直接echo对象时自动调用
  • _ _invoke():直接把对象当成函数调用时自动调用
  • _ _clone() :当 clone复制一个对象时,新创建的对象会自动调用类中的此函数
  • _ _debugInfo() :直接var_dump对象时自动调用
  • 官网示范用例:魔术方法----重载----构造函数和析构函数----对象复制

(2)类的自动加载

spl_auto_register('autoload1');
function autoload1($class_name){
	echo '<br>准备在autoload1中加载这个类:',$class_name;
	$file = './class/'.$class_name.'.class.php';
	if(file_exists($file)){
		include_once $file;
	}
}

(3)内置标准类

  • 内置标准类里面什么都没用,class stdclass{}
    作用:1.用于存储一些临时的简单的数据
       2.在类型转换时用于存储数据
$obj1 = new stdclass();
var_dump($obj1);//object(stdClass)[1]
class A{}
$obj2 = new A();
var_dump($obj2);//object(A)[2]
  • 对象的类型转换:$obj = (object)其他数据类型;
    说明:1.数组转换成对象,数组的键名当做属性名,值为对象对应的值
       (数字下标的数据元素,转换为对象后的属性,无法通过对象语法获取,因此不推荐转换)
       2.null转换为对象:空对象
       3.其他标量数据转换为对象:属性名为固定的”scalar“,值为该变量的值
$arr = array('pp1' => 1, 5 => 12);
$obj = (object)$arr;
var_dump($obj );
echo $obj ->pp1;		//1
echo $obj2->5;			//会报错!
$v1 = 1;       
$objv1 = (object)$v1;    //整型转为对象类型
var_dump($objv1);		//object(stdClass)[1]  public 'scalar' => int 1

(4)与类相关的系统函数

  • class_exist(“类名”):判断一个类是否存在/是否定义过
  • interface_exist(“接口名”):判断一个接口是否存在/是否定义过
  • get_class($obj):获得某个对象$obj的所属类
  • get_parent_class($obj):获得某个对象$obj的父类
  • get_class_methods():获得一个类的所有方法名,返回结果是一个数组,存储的是方法的名称
  • get_class_vars():获得一个类的所有属性名,返回结果是一个数组,存储的是属性的名称
  • get_declared_classes()/get_declared_interfaces:返回一个数组包含当前脚本所有已声明的类/接口的名称

(5)与对象相关的系统函数

  • is_object($obj):判断某个变量是否是一个对象
  • is_a(object,classname):判断对象是否为某类的对象
  • get_object_vars($obj):获得一个对象的所有属性,结果一个数组存储属性的名称

(6)与类有关的运算符

  • new:新建一个对象
  • clone:克隆一个对象
  • instanceof:判断一个变量/对象/数据是否是某个类的实例
class A{}    		   $a = new A();
class B{}  			   $b = new B();
class C extends A{}    $c = new C();
$v1 = $a instanceof A;    //true
$v2 = $b instanceof A;    //false
$v3 = $c instanceof C;    //true
$v4 = $c instanceof A;    //true

(7)static、self

  • self:代表这个单词本身所在位置的所在类
       (写在哪个类里面, 实际调用的就是这个类)
  • static:代表的是调用当前方法的类
       (代表使用的这个类, 就是你在父类里写的static,然后被子类覆盖,使用的就是子类的方法或属性)
class A { 
    public static function who() { 
        echo __CLASS__; 
    } 
    public static function test() { 
        self::who(); 
//        static::who(); 
    } 
} 
A::test(); 
   
class B extends A { 
    public static function who() { 
        echo __CLASS__; 
    } 
} 
echo B::test(); 
   
如果使用关键字self运行结果:  A A   
如果使用关键字static运行结果:A B

(8)面向对象的三个特征

  • 封装:尽可能将一个类私有化,只开放那些必不可少的对外的属性和方法
       (能private就不要protected,能protected就不要public)
  • 继承:面向对象的基本思想和基本做法
  • 多态:1.不同对象使用相同的方法会表现出不同的结果
       2.同一个对象使用相同的方法也可能会表现为不同的结果,称“方法重载现象”

12.header(string,replace,http_response_code)

  • 向客户端发送原始的 HTTP 报头
  • 参数:
    string:规定要发送的报头字符串
    replace:指示该报头是否替换之前的报头,或添加第二个报头,默认是 true(替换)。false(允许相同类型的多个报头)
    http_response_code:可选。把 HTTP 响应代码强制为指定的值
  • 例子1:跳转页面
header('Location: https://blog.csdn.net/u010365335');
  • 例子2:控制浏览器缓存
    gmdate():将一个时间戳,格式化成GMT时间,格林威治时间
$expire = gmdate('D,d M Y H:i:s',time()+3).' GMT';
header("Expires:".$expire);							//缓存3秒
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");	//过期时间
header("Last-Modified:".$expire);					//设置页面最后更新时间
header("Cache-Control: no-cache");					//不设置缓存
header("Pragma: no-cache");
header("Expires: 0");
  • 例子4:声明content-type,页面编码
header('content-type:text/html;charset=utf-8');
  • 例子5:返回response状态码
header('HTTP/1.1 404 Not Found');
  • 例子6:在某个时间后执行跳转
header('Refresh: 10; url=https://blog.csdn.net/u010365335');  //10s后跳转。
//输出文件MIME类型
header("Content-type:application/pdf");

// 文件将被称为 downloaded.pdf
header("Content-Disposition:attachment;filename='downloaded.pdf'");

// PDF 源在 original.pdf 中
readfile("original.pdf");

13.性能优化

  • (1)使用isset()代替strlen
if(strlen($str)<5)){……}
if(!isset($str[5])){……}
  • (2)使用str_split分隔字符串比explode快
  • (3)如果是单个字符替换,用strtr比str_replace快
    strtr($string, $from, $to)或strtr($string, $array)
    str_replace($find, $replace, $string[, $count])
    在替换之前可以先用strpos查找,判断是否需要替换
// 使用三个参数
echo strtr('hello', 'e', '');   	 // 输出 hello
// 使用数组
echo strtr('hello', ['e' => '']);    // 输出 hllo
echo str_replace("red","pink","blue,red,green,yellow");	//blue,pink,green,yellow

14.PHP7新特性

(1)引入类型说明:形参、返回值

  • 默认情况下,形参类型声明不是被完全限制的,即程序期望得到一个整数型的参数,但我们可以传递一个浮点数,但可以做出一些限制,如declare(strict_type=1):强制类型保持一致,之后如果传递参数类型不一致,将会扔出Fatal错误
class Person{
	public function age(int $age):string	//形参类型:整数,返回值类型:字符串
	{}
	public function age(int $age):Address   //形参类型:整数,返回值类型:对象
	{
		return new Address();
	}
}

(2)use声明

//  非混合模式的 use 声明
use Publish\Packet\{Book,Ebook,Video,Presentation};
use function Publish\Packet\{getBook,saveBook};
use const Publish\Packet\{COUNT,KEY};
//  混合模式的 use 声明
use Publish\Packet\{Book,Ebook,Video,Presentation,
	function getBook,function saveBook,
	const COUNT,const KEY};
//  复合模式的 use 声明
use Publish\Packet\{
	Paper\Book,
	Electronic\Ebook,
	Media\Video
	};

(3)匿名类

  • 不用设置类名的类,同样可以继承接口和类,也可以在一个类中嵌套使用匿名类
//    不用设置类名的类
$name = new class(){
	public function __construct(){ echo 'yyfs';}
}
//    继承其他类和接口
interface Publishes{ public function getName(); }
class Packet { protected $name;}
$info = new class(...) extends Packet implements Publishes{...}
//    在一个类中嵌套使用匿名类
class Math{
	public function multiplySum(){
		return new class extends Math{
			public funtion multi(){}
		}
	}
}
//调用
$math = new Math();
echo $math->multiplySum()->multi(2);

(4)新操作符

  • <=>:太空飞船操作符,用于比较变量,当符号两边相等时返回0,右边大于符号左边,返回 -1 ,左边大于符号右边,返回 1,例 $int1 <=> $int2
  • ??:null合并运算操作符,原本是 $post = $_POST[‘title’] ? $_POST[‘title’] : null;
    现在可以$post = $_POST[‘title’] ?? null;
  • intval(x, y):整除运算符, intval( 10, 3) = 3

(5)统一变量语法

  • 解析代码的顺序默认从左到右
class Packet{
	public $title = 'PHP7';
	public function getTitle():string
	{ return $this->title;}
}
$method = ['title' => 'getTitle'];
$object = new Packet();
echo 'Book:' . $object->$method['title']();
  • 在PHP5.x中可以正常允许,但在PHP7中会首先尝试解析$object->$method,之后才会去尝试解析[‘title’]等,这并不符合预期,因此需要修改为echo ‘Book:’ . $object->{$method[‘title’]}();即可

(6)session_strat中可添加参数

  • 设置信息将会覆盖php.ini中的session配置
session_start(['cookie_lifetime'=>3600,'read_and_close'=>true]);

(7)unseriazlize

  • PHP7之前,unseriazlize并不安全,可以反序列化任何类型的对象,PHP7之后添加了过滤器,可以防止非法数据进行代码注入,提供了更安全的反序列化数据
class MyClass1 {  
   public $obj1prop;    
} 
class MyClass2 { 
   public $obj2prop; 
} 
$obj1 = new MyClass1(); 
$obj1->obj1prop = 1; 
$obj2 = new MyClass2(); 
$obj2->obj2prop = 2; 

$serializedObj1 = serialize($obj1); 	//序列化
$serializedObj2 = serialize($obj2); 

// 默认行为是接收所有类allowed_classes=true ,第二个参数可以忽略 
// 如果 allowed_classes 设置为 false, unserialize 将不会把对象转换为 __PHP_Incomplete_Class 对象 
$data = unserialize($serializedObj1 , ["allowed_classes" => false]); 
// 只允许 MyClass1 和 MyClass2 转换到 __PHP_Incomplete_Class 
$data2 = unserialize($serializedObj2 , ["allowed_classes" => ["MyClass1", "MyClass2"]]); 

print($data->obj1prop); 	//报错Notice
print($data2->obj2prop); 	//2

(8)支持Unicode字符格式

echo "\u{771f}\u{9999}";	//真香
  • PHP7环境下输出“真香”,早起版本原样输出

15.性状

  • 类似于类/接口,PHP解释器在编译时会把性状复制粘贴到类的定义体中,但是不会处理这个操作引入的不兼容问题。如果性状假定类中有特定的属性或方法,即在性状中没有定义,要确保相应的类中有对应的属性和方法。
    PHP性状——他人文章
  • 创建性状
trait MyTrait{
	//性状的实现,与实现类/接口类似
}
  • 使用性状
class MyClass{
	use MyTrait; //不同于引入命名空间
	//类的其他实现
}

16.生成器

  • yield,类似于迭代器,可以不要求类实现Iterator接口,减轻类的负担
/***************  该段代码没有用生成器,没有善用内存  ***************/
function makeRange($length)
{
    $dataset = [];
    for ($i = 0; $i < $length; $i++) {
        $dataset[] = $i;
    }
    return $dataset;
}

$time1 = microtime(true);
$range = makeRange(1000000);
foreach ($range as $v) {
}
echo '<br>';
$time2 = microtime(true);
echo '耗时:' . round($time2 - $time1, 3) . '秒<br>';
echo '内存消耗: ' . memory_get_usage() / 1024 . 'KB<br>';
/***************  使用生成器,内存消耗极小  ***************/
function makeRange($length)
{
    for ($i = 0; $i < $length; $i++) {
        yield $i;
    }
}

$time1 = microtime(true);
$range = makeRange(1000000);
foreach ($range as $v) {
}
$time2 = microtime(true);
echo '耗时' . round($time2 - $time1, 3) . '秒<br>';			//耗时:0.057秒
echo '内存消耗: ' . memory_get_usage() / 1024 . 'KB<br>';	//内存消耗: 338.5234375KB

17.PHP常用参数

(1)php.ini

1、Zend OPcache

设置PHP内置字节码缓存功能

  • opcache.memory_consumption = 64: 为操作码缓存分配的内存制,单位为MB,小型PHP引用可以设置16MB,大型可以设置64-256MB
  • opcache.interned_strings_buffer = 16:用来存储驻留的字符串的内存量,默认值为4MB
  • opcache.max_accelerated_files=5000:最大缓存的文件数目, 命中率不到 100% 的话, 可以试着提高这个值,值一定要比PHP引用的文件数量大
  • opcache.validate_timestamps=1:设置为1时,经过一段时间后PHP会检查脚本内的内容是否有变化,检查的时间间隔由opcache.revalidate_freq设置指定。如果这个设置的值为0,则PHP不会检查脚本内容辩护,必须手动清除缓存的操作码,建议在开发环境设为1,在生产环境设为0
  • opcache.revalidate_freq=240:设置PHP多久的时间周期回去检查仪器脚本的内容是否有变化,默认为 2, 单位为秒
  • opcache.fast_shutdown=1: 是否快速关闭, 能让操作码使用更快的停机步骤,把对象析构和内存释放交给ZendEngine的内存管理器完成,打开后在PHP Request Shutdown的时候回收内存的速度会提高
  • opcache.save_comments=0:不保存文件/函数的注释
2、文件上传参数

PHP文件操作-上传,下载(断点续传),目录操作,文件操作

3、缓存输出
  • output_buffering=4096:off为关闭输出缓存,on为打开无限大的输出缓存,数值则打卡单位为B的输出缓存
  • implicit_flush=false:打开或关闭绝对刷送,on:每次输出(如echo,print)后自动调用flush()函数后,直接输出;off:与On相反,每次输出后不会调用flush(),需要等到server buffering满了才会输出,但是我们可以用flush()函数代替它,不开启也没关系,反而更加灵活
  • realpath_cache_size=256K:获取真实路径缓冲区的大小,使用大量文件时,增大该值可以优化性能

(2)PHP-FPM.conf

  • user=www-data:拥有这个PHP-FPM进程中子进程的系统用户
  • group=www-data:拥有这个PHP-FPM进程池中子进程的系统用户组
  • listen=127.0.0.1:9000:可以使用任意大于1024的端口,PHP进程池监听的IP地址和端口
  • listen.allowed_clients:127.0.0.1:可以向这个PHP-FPM进程池发送请求的IP地址,一个或多个
  • pm.max_children=51:设置任何时间点PHP-FPM进程池中最多能有几个进程,每个PHP进程使用5-15MB内存,假设设备为PHP-FPM进程池分配了512MB可用内存,则设置512/10MB=51个进程
  • pm.start_servers=3:PHP-FPM进程池中立即可用的进程池,一般设置为2-3个
  • pm.min_spare_servers=2:PHP应用空闲时PHP-FPM进程池中可以存在的进程数量的最小值
  • pm.max_spare_servers=4:PHP应用空闲时PHP-FPM进程池中可以存在的进程数量的最大值
  • pm.max_requeset=1000:回收进程之前,PHP-FPM进程池中各个进程最多能处理的HTTP请求数量
  • showlog=/path/to/showlog.log:为一个日志文件在文件系统中的最对路径,用于记录处理时间超过 n 秒的HTTP请求信息,以便找出PHP应用的瓶颈,进行调试,PHP-FPM进程池所属的用户和用户组必须有这个文件的写权限
  • request_showlog_timeout=51:如果当前HTTP请求的处理时间超过指定值,就把请求的回溯信息写入slowlog设置的日志文件中

-----小Tips

  • unset():删除的只是元素的值,而所占有的空间还保留着
  • 性能分析工具,XHProf,ab
  • 赋值字符串的指定位置具体字符时,只会把第一个值赋上
$text = 'Jony';
$test[10] = 'YY-帆S';  // 则$text[10] = 'Y';
echo $text; 		  // Jony      Y ,Jony后面有六个空格
echo strlen($text);   // 11
;