php

PHP面试题收集

2020-03-05  本文已影响0人  皮蛋馅儿

一、字符串的定义方式和各自区别

$str = <<<EOF

EOF;
$str = <<<'EOF'

EOF;

二、三大数据类型

整型0,  浮点0.0,  空字符串'',  0字符串'0',  布尔false ,  空数组array(),  NULL

③超全局数组

$GLOBALS    $_SERVER    $_GET    $_POST 
$_FILES     $_COOKIE    $_SESSION    $_REQUEST    $_ENV
$_SERVER['SERVER_ADDR']   服务端的ip地址
$_SERVER['REMOTE_ADDR']   客户端的ip地址

获取客户端 IP 都要依次获取 HTTP_CLIENT_IP 、HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR 

HTTP_CLIENT_IP: 头是有的,只是未成标准,不一定服务器都实现了。

X-Forwarded-For(XFF):  是用来识别通过http代理或者负载均衡连接到web服务器的客户端最原始的IP地址的HTTP请求头字段,格式:clientip,proxy1,proxy2

REMOTE_ADDR: 是可靠的, 它是最后一个跟你的服务器握手的IP,可能是用户的代理服务器,也可能是自己的反向代理。

④为NULL的三种情况
直接赋值为null、未定义的变量、unset销毁的变量
⑤常量定义(常量一经定义,不能修改,不能删除)
const 更快,是语言结构,可以定义类常量
define 是函数,不能定义类常量
预定义常量

__FILE__ 文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名
__LINE__ 文件中的当前行号
__DIR__文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录
__FUNCTION__ 函数名称
__CLASS__ 类的名称
__TRAIT__ Trait 的名字
__METHOD__ 类的方法名
__NAMESPACE__ 当前命名空间的名称(区分大小写)

三、内置函数(参见PHP官网的字符串和数组内置函数)

array_shift() 删除数组第一个元素;并返回被删除元素的值
array_pop() 删除数组最后一个元素;并返回被删除元素的值
array_unshift() 向数组头部插入新元素;返回新数组元素的个数
array_push() 向数组尾部插入新元素;返回新数组元素的个数

四、正则表达式
作用:分割、查找、匹配、替换字符串

========== 匹配139开头的手机号码==========
'/^139\d{8}$/'

==========匹配img标签里面的src的值==========
'/<img.*?src="(.*?)".*?\/?>/i'
注意:
(.*)是后向引用
前面加?是禁止贪婪,最后一个问号表示重复前面内容的0次或一次,

五、文件目录操作

===================== 在一个文件的开头加入指定字符串=====================
// 打开文件
$file = 'file.txt';
$handle = fopen($file, 'r');
// 将文件的内容读取出来,在开头加入hello
$content = fread($handle, filesize($file));
$content = 'hello~' . $content;
fclose($handle);
// 将拼接好的字符串写回文件
$handle = fopen($file, 'w');
fwrite($handle, $content);
fclose($handle);


=====================遍历一个目录下的所有文件=====================
public function loopDir($dir)
{
    $array = [];
    if (is_dir($dir)) {
        // 打开目录
        $handle = opendir($dir);
        while ($file = readdir($handle)) {
            if ($file == '.' || $file == '..') {
                continue;
            }

            $fileDir = $dir . '/' . $file;
            if (is_file($fileDir)) {
                $array[] = $file;
            } else if (is_dir($fileDir)) {
                $array[$file] = $this->loopDir($fileDir);
            }
        }
        closedir($handle);
    }
    return $array;
}

六、会话控制
=======================SESSION和COOKIE =======================
SESSION存储在服务器端,COOKIE保存在客户端。Session比较安全,cookie用某些手段可以修改,不安全。Session依赖于cookie进行传递。禁用cookie后,session还可以使用,在存储session的文件中,生成sessionID,通过get传参的方式将sessionID传到要实现session共享的页面,读取sessionID,从而从session中获取数据。

关闭cookie,使用session的方法
设置php.ini配置文件中的“session.use_trans_sid = 1”,或者编译时打开打开了“--enable-trans-sid”选项,让PHP自动跨页传递Session ID。
手动通过URL传值、隐藏表单传递Session ID。
用文件、数据库等形式保存Session ID,在跨页过程中手动调用。

总结一下,上面的方法有一个共同点,就是在前一页取得Session ID,然后想办法传递到下一页,在下一页的session_start();代码之前加代码Session ID(传过来的Session ID)。

=======================session的垃圾回收机制=======================
session.gc_maxlifetime = 1440(Session数据在服务器端储存的时间)
session.gc_probability = 1
session.gc_divisor = 100

session.gc_divisor 与 session.gc_probability 合起来定义了在每个会话初始化时启动 gc(garbage collection 垃圾回收)进程的概率。此概率用 gc_probability/gc_divisor 计算得来。例如 1/100 意味着在每个请求中有 1% 的概率启动 gc 进程。session.gc_divisor 默认为 100。

GC 的工作,就是扫描所有的session信息,用当前时间减去session的最后修改时间(modifieddate),同session.gc_maxlifetime参数进行比较,如果生存时间已经超过gc_maxlifetime,就把该session删除

七、面向对象

1. __construct  具有构造函数的类会在每次创建新对象时先调用此方法
2. __destruct  对象的所有引用都被删除或者当对象被显式销毁时执行。
3.__call()  在对象中调用一个不可访问方法时会被调用。
4.__callStatic()  在静态上下文中调用一个不可访问方法时会被调用。
5.__set()   在给不可访问的属性赋值时调用
6.__get()  读取不可访问的属性值时自动调用
7.__isset()  当对不可访问的私有属性使用isset或empty时自动调用
8.__unset()  当对不可访问的私有属性使用unset时自动调用
9.__toString() 当一个类的实例对象被当成一个字符串输出时调用
10.__invoke()将一个PHP对象当成一个函数执行时会回调
11.__clone()克隆一个对象

1.工厂模式,工厂方法或者类生成对象,而不是在代码中直接new

class Factory
{
    public static function createDatabase()
    {
        $db = new Database();
        return $db;
    }
}

调用:Factory::createDatabase();

查看PHP工厂模式
使用场景:假如很多个地方都用到同个类的new操作,如果修改了这个类的名称或者这个类的一些参数发生了一些变化,那么每个地方都要修改,用工厂模式可解决此问题

2.单例模式,使某个类的对象仅允许创建一个
查看PHP单例模式

3.注册模式,全局共享和交换对象
查看PHP注册模式

4.适配器模式,将截然不同的函数接口封装成统一的API
查看PHP适配器模式

5.策略模式,将一组特定的行为和算法封装成类,以适应某些特定的上下文环境
查看策略模式

八、网络协议
HTTP协议状态码
常见状态码:

网络7层协议(OSI七层模型)
7 应用层 (协议有HTTP/HTTPS/FTP/SMTP/DNS等)
6 表示层
5 会话层
4 传输层 (协议有TCP/UDP)
3 网络层
2 数据链路层
1 物理层
7、6、5、4层定义了应用程序的功能
3、2、1层主要面向通过网络的端到端的数据流

常见的网络协议含义以及端口

CGI:是 Web Server 与 Web Application 之间数据交换的一种协议。
FastCGI:同 CGI,是一种通信协议,但比 CGI 在效率上做了一些优化。同样,SCGI 协议与 FastCGI 类似。
PHP-CGI:是 PHP 对 Web Server 提供的 CGI 协议的接口程序。
PHP-FPM:是 PHP 对 Web Server 提供的 FastCGI 协议的接口程序( 进程管理器),额外还提供了相对智能一些任务管理。

WEB 中,
Web Server 一般指Apache、Nginx、IIS、Lighttpd、Tomcat等服务器,
Web Application 一般指PHP、Java、Asp.net等应用程序。

九、AJAX的工作原理
XMLHttpRequest是AJAX的基础
XMLHttpRequest用于在后台与服务器交换数据
客户端发送请求,请求交给xhr,xhr把请求提交给服务,服务器进行业务处理,服务器响应数据交给xhr对象,xhr对象接收数据,由javascript把数据写到页面上

十、Linux
Linux常用命令

解压
tar -xvf file.tar //解压 tar包
tar -xzvf file.tar.gz //解压tar.gz
tar -xjvf file.tar.bz2 //解压 tar.bz2
tar -xZvf file.tar.Z //解压tar.Z
unrar e file.rar //解压rar
unzip file.zip //解压zip

总结
1、.tar 用 tar -xvf 解压
2、
.gz 用 gzip -d或者gunzip 解压
3、.tar.gz和.tgz 用 tar -xzf 解压
4、.bz2 用 bzip2 -d或者用bunzip2 解压
5、
.tar.bz2用tar -xjf 解压
6、.Z 用 uncompress 解压
7、
.tar.Z 用tar -xZf 解压
8、.rar 用 unrar e解压
9、
.zip 用 unzip 解压

系统定时任务
crontab命令
crontab -e # 创建一个任务调度,会进入到vi编辑界面,编写要调度的任务
crontab -l # 列出定时的任务
crontab -r con_name # 删除crontab文件
which ifconfig # 获取命令路径

* * * * * 命令(分 时 日 月 周)

每天0点重启服务器
0 0 * * * reboot

十一、MySQL
1、varchar和char的区别

因为char长度固定,所以存取速度要比varchar快得多,但是char因为其长度固定,所以会占据多余的空间,可谓是以空间换取时间效率。varchar则刚好相反,以时间换空间。

2、数据库引擎
InnoDB:数据存储在共享表空间,对主键查询的性能高于其他类型的存储引擎。
支持事务处理,支持外键,支持行级锁,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。

MyISAM:拥有全文索引、压缩、空间函数。
不支持事务和行级锁,不支持奔溃后的安全恢复,表存储在MYD和MYI两个文件,设计简单,某些场景下(比如 select count(*))性能很好。

MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。

merge:用于日志和数据仓库

archive:用于日志,只有select和insert,不支持索引。

以下两点必须使用InnoDB:
1)可靠性高或者要求事务处理,则使用InnoDB。这个是必须的。
2)表更新和查询都相当的频繁,并且表锁定的机会比较大的情况指定InnoDB数据引擎的创建。
对比之下,MyISAM的使用场景:
1)做很多count的计算的。如一些日志,调查的业务表。
2)插入修改不频繁,查询非常频繁的。

3、MySQL索引
索引对性能的影响

索引使用场景

索引类型

索引创建原则:

通俗理解口诀:
全值匹配我最爱,最左前缀要遵守;(复合索引)
带头大哥不能死,中间兄弟不能断;(复合索引)
索引列上少计算,范围之后全失效;
LIKE百分写最右,覆盖索引不写星;
不等空值还有or,索引失效要少用。

4、分析SQL语句查询速度慢的方法

5、MySQL语句优化
①优化查询过程中的数据访问

②优化长难的查询语句

③优化特定类型查询语句

6、分区和分表
分区:就是把一个数据表的文件和索引分散存储在不同的物理文件中。 表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的、容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。

分表: 通过一定规则,将一张表(垂直或者水平)分解成多张不同的表,每一个小表都是完整的一张表

分表与分区的区别:
实现方式上:分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。

数据处理上:分表后数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。分区则不存在分表的概念,分区只不过把存放数据的文件分成了许多小块,分区后的表还是一张表,数据处理还是由自己来完成。

提高性能上:分表后,单表的并发能力提高了,磁盘I/O性能也提高了。分区突破了磁盘I/O瓶颈,想提高磁盘的读写能力,来增加mysql性能。
在这一点上,分区和分表的侧重点不同,分表重点是存取数据时,如何提高mysql并发能力上;而分区呢,如何突破磁盘的读写能力,从而达到提高mysql性能的目的。

实现的难易度上:分表的方法有很多,用merge来分表,是最简单的一种方式。这种方式和分区难易度差不多,并且对程序代码来说可以做到透明的。如果是用其他分表方式就比分区麻烦了。 分区实现是比较简单的,建立分区表,跟建平常的表没什么区别,并且对代码端来说是透明的。
分区和分表的目的就是减少数据库的执行负担,稳定SQL性能。

分区
mysql支持的分区类型包括Range、List、Hash、Key

CREATE TABLE user (
    id INT NOT NULL auto_increment,
    username VARCHAR (10),
    PRIMARY KEY (id)
) ENGINE = INNODB charset = utf8 PARTITION BY RANGE (id)(
    PARTITION user_1 VALUES less than (10),
    PARTITION user_2 VALUES less than (20),
    PARTITION user_3 VALUES less than MAXVALUE
);

表分区好处:

分区限制

分表

// 创建一个完整表存储着所有的成员信息
CREATE TABLE `member` (
`id`  int(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
`name`  varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET = utf8 AUTO_INCREMENT = 1;

// 插入数据(第2条语句多执行几次就有了很多数据):
insert into member(name) values('a');
insert into member(name) select name from member;

// 创建两个分表tb_member1,tb_member2
DROP TABLE IF EXISTS tb_member1;
CREATE TABLE tb_member1 (
`id` INT (10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR (20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE = MyISAM DEFAULT CHARSET = utf8 AUTO_INCREMENT = 1;

DROP TABLE IF EXISTS tb_member2;
CREATE TABLE tb_member2 LIKE tb_member1;

// 创建主表tb_member
DROP TABLE IF EXISTS tb_member;
CREATE TABLE tb_member (
`id` INT (10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR (20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE = MERGE UNION = (tb_member1, tb_member2) INSERT_METHOD = LAST CHARSET = utf8 AUTO_INCREMENT = 1;

// 把数据分到两个分表中去
insert into tb_member1(id, name) select id,name from member where id%2=0;
insert into tb_member2(id, name) select id,name from member where id%2=1;

分表存在的问题:

分表的几种常见方法:

7、MySQL主从复制
MySQL之间数据复制的基础是二进制日志文件(binary log file)。
Master 将改变记录到二进制日志中。
Slave 将 Master 的二进制日志拷贝到它的中继日志( Relay_log )
Slave 重做中继日志中的事件,将改变反映它自己的数据

MySQL主从复制解决的问题

8、MySQL安全

SQL查询安全解决方案

MySQL其他安全设置

9、数据表创建命令

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `username` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
  `password` char(32) NOT NULL DEFAULT '' COMMENT '密码',
  `phone` varchar(11) NOT NULL DEFAULT '' COMMENT '手机号码',
  `token` varchar(100) NOT NULL DEFAULT '' COMMENT 'app登录token',
  `create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '添加时间',
  `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态,-1删除,0待审,1正常',
  PRIMARY KEY (`id`),
  KEY `phone` (`phone`) USING BTREE,
  KEY `token` (`token`) USING BTREE
) ENGINE=InonoDB DEFAULT CHARSET=utf8mb4;

10、PHP连接数据库的方式

PDO操作数据库

$pdo = new \PDO("mysql:host=$host;dbname=$dbname", $user, $name);
$sql = 'SELECT id, username FROM user WHERE id=:id';
$prepare = $pdo->prepare($sql);
$prepare->execute([':id' => $id]);
$result = $prepare->fetchAll(\PDO::FETCH_ASSOC);

十二、MVC
单一入口:用一个处理程序文件处理所有的HTTP请求,根据请求参数的不同区分不同模块和操作

好处:

框架对比
ThinkPHP 5 是一个为API开发而设计的高性能框架,采用全新的架构思想,引入了很多的PHP新特性,优化了核心,减少了依赖,实现了真正的惰性加载,支持composer,并针对API开发做了大量的优化。
规范:遵循PSR-2、PSR-4规范,Composer及单元测试支持;
严谨:异常严谨的错误检测和安全机制,详细的日志信息;
灵活:减少核心依赖,扩展更灵活、方便,支持命令行指令扩展;
API友好:出色的性能和REST支持、远程调试,更好的支持API开发;
高效:惰性加载,及路由、配置和自动加载的缓存机制;
ORM:重构的数据库、模型及关联,MongoDb支持;

Yii2是一个通用的 Web 编程框架,即可以用于开发各种用 PHP 构建的 Web 应用。 因为基于组件的框架结构和设计精巧的缓存支持,它特别适合开发大型应用, 如门户网站、社区、内容管理系统(CMS)、 电子商务项目和 RESTful Web 服务等。

laravel框架的设计思想比较先进,非常适合应用各种开发模式,作为一个框架,它为你准备好了一切。
laravel框架最大的特点和优秀之处就是集合了php比较新的特点,以及各种各样的设计模式,Ioc模式,依赖注入等。
强大的rest router:用简单的回调函数就可以调用,快速绑定controller和router
artisan:命令行工具,很多手动的工作都自动化
可继承的模板,简化view的开发和管理
blade模板:渲染速度更快
ORM操作数据库
migration管理数据库和版本控制
composer也是亮点
测试功能也很强大

CodeIgniter 是一个小巧但功能强大的 PHP 框架,特点:简单、小巧、出色的性能、安全、几乎0配置

十三、算法
算法的特征:有穷性、确切性、输入项、输出项、可行性

1、冒泡排序:两两相邻的数进行比较,如果反序就交换,否则不交换
如数组:$sort = [6,1,2,4,5,3]; 进行冒泡排序(从小到大)
第一轮:
 第一次:1,6,2,4,5,3
 第二次:1,2,6,4,5,3
 第三次:1,2,4,6,5,3
 第四次:1,2,4,5,6,3
 第五次:1,2,4,5,3,6

第二轮:
 第一次:1,2,4,5,3,6
 第二次:1,2,4,5,3,6
 第三次:1,2,4,5,3,6
 第四次:1,2,4,3,5,6

第三轮:
 第一次:1,2,4,3,5,6
 第二次:1,2,4,3,5,6
 第三次:1,2,3,4,5,6

第四轮:
 第一次:1,2,3,4,5,6
 第二次:1,2,3,4,5,6

第五轮:
 第一次:1,2,3,4,5,6

<?php
$arr = [6, 7, 3, 5, 9, 10, 1];
$length = count($arr);
// 轮
for ($i = 1; $i < $length; $i++) {
    // 次
    for ($j = 0; $j < $length - $i; $j++) {
        if ($arr[$j] > $arr[$j + 1]) {
            $tmp = $arr[$j];
            $arr[$j] = $arr[$j + 1];
            $arr[$j + 1] = $tmp;
        }
    }
}
echo '<pre>';
print_r($arr);

2、时间复杂度计算方式:
O(n^2)、 O(1)、 O(n)

3、

// 把my_user_name转换成MyUserName
$newStr = '';
$str = 'my_user_name';
$arr = explode('_', $str);
foreach ($arr as $value) {
    $newStr .= ucfirst($value);
}


//  字符串反转
第一种:$str ='abc';
for ($i = 0; true; $i++) {
    if (!isset($str[$i])) break;
}

$newStr = '';
for ($j = $i -1 ;$j >= 0; $j --) {
    $newStr .= $str[$j];
}

第二种: $str = 'abcde';
$newStr = '';
for ($i = strlen($str) - 1; $i >= 0; $i--) {
    $newStr .= $str[$i];
}

第三种:function mb_strrev($str)
{
    $r = '';
    for ($i = mb_strlen($str); $i >= 0; $i--) {
        $r .= mb_substr($str, $i, 1);
    }
    return $r;
}
echo mb_strrev("☆❤world我"); 
// 我dlrow❤☆


// 实现array_merge(数组合并)
function arrayMerge()
{
    $return = [];
    $arrays = func_get_args();
    foreach ($arrays as $arr) {
        if (is_array($arr)) {
            foreach ($arr as $val) {
                $return[] = $val;
            }
        }
    }
    return $return;
}


//奇偶数
$a = [6, 7, 8, 9];
$arr = array_filter($a, function ($v) {
    return ($v & 1);
});
返回:
[
  1 => 7
  3 => 9
]


// 读取文件里面的内容
第一种:
$file = 'E:\php1\wamp64\www\test.txt';
$content = file($file);
foreach ($content as $key => $value) {
    $value = mb_convert_encoding($value, 'utf-8', 'gbk');
    $v = explode("\t", $value);
}

第二种:
$handle = fopen($file, 'r');
if ($handle) {
    while (($row = fgets($handle)) !== false) {
        $row = mb_convert_encoding($row, 'utf-8', 'gbk');
        $v = explode("\t", $row);
    }
    fclose($handle);
}


// 24个字母排序字符串
$arr = range('a', 'z');
$str = implode($arr);// abcdefghijklmnopqrstuvwxyz


// 交换两个变量的值
$a = "aa";
$b = "bb";
var_dump([$a, $b]); // ['aa', 'bb']
list($a, $b) = [$b, $a];
var_dump([$a, $b]); ['bb', 'aa']

十四、高并发
QPS:每秒钟请求或者查询的数量,在互联网领域,指的是每秒响应请求数(HTTP请求),QPS不等于并发连接数,并发连接数是系统同时处理的请求数量

吞吐量:单位时间内处理的请求数量(通常由QPS与并发数决定)

PV:综合浏览量(Page View),即页面浏览量或者点击量,一个访客在24小时内访问的页面数量
同一个人浏览网站的同一个页面,只记一次PV

UV:独立访客(Unique Visitor),即一定时间范围内相同访客多次访问网站,只计算为1个独立访客

带宽:计算带宽大小需要关注的两个指标,峰值流量和页面的平均大小

压力测试
测试能承受 最大并发
测试最大承受的QPS值

常用的性能测试工具:ab、wrk、http_load等

ab(apache benchmark),是apache官方推出的工具。
创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问。
它的测试目标是基于URL的,因此它既可以用来测试Apache的负载压力,还可以测试nginx、lighthttp、tomcat、IIS等其他web服务器的压力。

注意:

// 模拟并发请求100次,总共请求5000次
ab -c 100 -n 5000 待测试网站

高并发解决方案
1、流量优化
(1) 防盗链处理(去除恶意请求)
(2) 控制大文件的下载。
(3) 确认服务器硬件是否足够支持当前的流量
(4) 使用流量分析统计软件
(5) 尽量使用静态页,缓存

2、前端优化
(1) 减少HTTP请求[将css、js等合并、使用图片地图或者CSS精灵、图片Base64编码]
(2) 添加异步请求(先不将所有数据都展示给用户,用户触发某个事件,才会异步请求数据)
(3) 启用浏览器缓存和文件压缩
(4) CDN加速
(5) 建立独立的图片服务器(减少I/O)

3、服务端优化
(1) 页面静态化(使用模板引擎、利用ob系列函数)
(2) 并发处理
(3) 队列处理

4、数据库优化
(1) 数据库缓存
(2) 分库分表,分区
(3) 读写分离
(4) 负载均衡

5、web服务器优化
(1) nginx反向代理实现负载均衡
(2) lvs实现负载均衡

十五、进程、线程、协程
进程三态模型:运行、就绪、阻塞
进程五态模型:新建态、活跃就绪/静止就绪、运行、活跃阻塞/静止阻塞、终止态

线程:有时被称为轻量级进程,是程序执行流的最小单元

线程状态:就绪、阻塞、运行

协程:是一种用户态的轻量级线程,协程的调度完全由用户控制

线程和进程的区别

线程和协程的区别

同步阻塞

// 创建一个socket
$sockServer = stream_socket_server('tcp://0.0.0.0:8000', $errno, $errstr);

for ($i = 0; $i < 5; $i++) {
    if (pcntl_fork() == 0) {
        while (true) {
            $conn = stream_socket_accept($sockServer);
            if ($conn == false) {
                continue;
            }

            $request = fread($conn, 9000);
            $response = 'hello';
            fwrite($conn, $response);
            fclose($conn);
        }
        exit(0);
    }
}
实现多进程并行操作(可做守护进程) 

/**
 * 入口函数
 * 将此文件保存为 ProcessOpera.php
 * 在terminal中运行 /usr/local/php/bin/php ProcessOpera.php &
 * 查看进程 ps aux|grep php
 */
ProcessOpera("runCode", [], 8);

/**
 * @param array $opt
 * run Code
 */
function runCode($opt = [])
{
    //需要在守护进程中运行的代码
}


/**
 * @param string $func 子进程执行具体事物的函数名称
 * @param array $opts $func的参数 数组形式
 * @param int $pNum fork的子进程数量
 */
function ProcessOpera($func, $opts = array(), $pNum = 1)
{
    while (true) {
        $pid = pcntl_fork();
        if ($pid == -1) {
            exit("pid fork error");
        }
        if ($pid) {
            static $execute = 0;
            $execute++;
            if ($execute >= $pNum) {
                pcntl_wait($status);
                $execute--;
            }
        } else {
            while (true) {
                // some code
                $func($opts);
                sleep(1);
            }
            exit(0);
        }
    }
}
实现多线程

class My extends Thread
{
    protected $param;
    protected $name;
    public $running;

    function __construct($name)
    {
        $this->running = 1;
        $this->param = 0;
        $this->name = $name;
    }

    public function run()
    {
        while ($this->running) {
            if ($this->param) {
                $time = rand(1, 5);
                echo 'I am thread ' . $this->name . ',pid: ' . $this->getCreatorId() . ",param: {$this->param},need {$time}s\n";
                sleep($time);
                $this->param = 0;
            } else {
                echo "Thread {$this->name} waiting...\n";
            }
            sleep(1);
        }
    }
}

$pool = [];
$pool[] = new My('a');
$pool[] = new My('b');
$pool[] = new My('c');
//开启所有线程
foreach ($pool as $w) {
    $w->start();
}
//派发任务
unset($w);
for ($i = 1; $i < 10; $i++) {
    $worker_content = $i;
    while (1) {
        foreach ($pool as $w) {
            if (!$w->param) {
                $w->param = $worker_content;
                echo "Thread {$w->name} empty,put param {$worker_content}.\n";
                break 2;
            }
        }
        sleep(1);
    }
}

unset($w);
while (count($pool)) {
    foreach ($pool as $k => $w) {
        if (!$w->param) {
            $w->running = false;
            unset($pool[$k]);
            echo "Thread {$w->name} end,exit!\n";
        }
    }
    sleep(1);
}

echo 'All thread end!';

PHP并发编程实践

缓存
memcache和redis的区别

web服务器的负载均衡
七层负载均衡:基于url等应用层信息的负载均衡
nginx的proxy是他一个很强大的功能,实现了七层负载均衡
特点:

实现

http {
    upstream my {
        server server1;
        server server2;
        server server3;
    }
    server {
        listen 80;
        location / {
            proxy_pass http://my;
        }
    }
}

加我微信公众号【皮蛋馅儿】,一起学习哦~

上一篇 下一篇

猜你喜欢

热点阅读