非科班的苦逼程序员,深感找工作的艰辛,而且还是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)类的自动加载
- _ _autoload():系统内部的自动加载函数
- spl_autoload_register(‘函数名’):注册更灵活的自动加载函数
- PHP实现路由器功能–未编写
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后跳转。
- 例子7:控制文件下载
CSDN:PHP文件操作-上传,下载(断点续传),目录操作,文件操作
//输出文件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、文件上传参数
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