PHP 2021面试题,一般所遇到的问题与答案,多达51题(持续更新)


GET 与 POST 的区别


**显示有区别**
get方法是将字符串拼接在地址栏后面可以看见
而post方法看不见

**传递的大小有区别**
具体大小和浏览器有关系,ie浏览器是2k其他浏览器的最大值可能不同,但是也比较小。
而post方法传递参数的大小是可以设定的,原来是认为无限大。在Php当中在php.ini文件是可以设置参数的大小的。

**安全性**
get方法安全性比较低因为暴露在外面而post方法安全性比较高

**提交的原理**
get方法提交的数据都是独立的。
而Post方法将所有的提交的数据变成一个整体(将提交的数据变成xml格式)

**灵活性**
get方法很灵活,
post方法不灵活,必须要有表单的参与才能用post提交很不方便


require,include区别


require 是无条件包含也就是如果一个流程里加入require,无论条件成立与否都会先执行require
include 有返回值,而 require 没有(可能因为如此 require 的速度比 include)
包含文件不存在或者语法错误的时候 require 是致命的错误终止执行,include 不是


获取URL后缀名


pathinfo() 解析文件路径,返回其组成部分;

$path = '/ab/cd/e.php';
 
print_r( pathinfo($path) );

结果:

Array(

  [dirname] => /ab/cd  # 文件路径

  [basename] => e.php  # 文件名+扩展名

  [extension] => php   # 最后一个扩展名

  [filename] => e  # 文件名

)

扩展:

打印解析路径    var_dump( pathinfo($path) );

打印路径的父级路径    var_dump( pathinfo($path, PATHINFO_DIRNAME) );

打印路径的尾名    var_dump( pathinfo($path, PATHINFO_BASENAME) );

打印路径的最后的扩展名   var_dump( pathinfo($path, PATHINFO_EXTENSION) );

打印路径的文件的名字   var_dump( pathinfo($path, PATHINFO_FILENAME) );


获取上级目录的方法


echo __FILE__ ; // 获取当前所在文件的绝对路径及地址,结果:F:\WWW\index.php

echo dirname(__FILE__); // 取得当前文件所在的绝对目录,结果:F:\WWW

echo dirname(dirname(__FILE__)); //取得当前文件的上一层目录名,结果:F:\


MySQL 数据库索引


**什么是索引**
索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。(摘自百度百科)

**索引类型**
1.FULLTEXT 全文索引
    全文索引,仅MyISAM引擎支持。其可以在CREATE TABLEALTER TABLECREATE INDEX 使用,不过目前只有 CHARVARCHARTEXT 列上可以创建全文索引。

2.HASH 哈希索引
    HASH索引的唯一性及类似键值对的形式十分适合作为索引,HASH索引可以一次定位,不需要像树形索引那样逐层参照,因此具有极高的效率。但是这种高效是有条件的。即只在“=”和“in”条件下高效,对于范围查询,排序及组合索引仍然效率不高。

3.BTREE 树形索引
    BTREE所以是一种将索引按一定算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,一次遍历node,获取leaf。这是MySQL中默认也是最常用的索引类型。

4.RTREE
    RTREE在MySQL中很少使用,仅支持geometry数据类型,支持该存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。相对于BTREERTREE的优势在于范围查找。

**索引种类**
普通索引:仅加速查询
唯一索引:加速查询+列值唯一(可以有null)
主键索引:加速查询+列值唯一(不可以有null+表中只有一个
组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
全文索引:对文本内容进行分词,进行搜索
外键索引:与主键索引形成联系,保证数据的完整性。

**从物理角度来讲**
1. 聚集索引
2. 非聚集索引

**索引使用的注意事项**
1.符合索引遵循前缀原则
2.like查询%不能再前,否则索引失效。如有需要,使用全文索引
3.column is null可以使用索引
4.如果MySQL估计使用索引比全表扫描慢,则放弃使用索引
5.如果or前的条件中列有索引,后面的没有,索引不会生效。
6.列类型是字符串,查询时,一定要给值加引号,否则索引失效。
7.确定order by 和 group by 中只有一个表的列,这样才能使用索引


高并发的解决方案


web服务器优化 :负载均衡

流量优化:防盗链处理 将恶意请求屏蔽,

前端优化:减少http请求、添加异步请求、启用浏览器缓存和文件压缩、cdn加速、建立独立的图片服务器、

服务端优化:  页面静态化、并发处理、队列处理、

数据库优化: 数据库缓存、分库分表、分区操作 、读写分离、负载均衡


MVC的理解


1、Model(业务模型):应用程序中用于处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据。          

2、view(视图):应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。

3、controller(控制器):应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。


InnoDB,MyISAM的区别


MyISAM:

不支持事务;

数据存储在磁盘,可被压缩,存储空间较小;

只支持表级锁;

支持(FULLTEXT类型的)全文索引。

保存有表的总行数,如果select count(*) from table,会直接取出该值;

如果执行大量的SELECT,MyISAM是更好的选择;

不支持外键;

 

InnoDB:

支持事务;

存储在共享空间,需要更多的内存和存储;

具有事务、回滚和崩溃修复能力;

只支持行级锁;

不支持(FULLTEXT类型的)全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好;

支持外键;

如果你的数据执行大量的INSERTUPDATE,出于性能方面的考虑,应该使用InnoDB表。

 

**MyISAM和InnoDB两者的应用场景:**

1) MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。
   如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。

2) InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。
   如果应用中需要执行大量的INSERTUPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。
   

接口与抽象类的区别


1. 接口:

  (1)对接口的使用是通过关键字implements2)接口不能定义成员变量(包括类静态变量),能定义常量

  (3)子类必须实现接口定义的所有方法

  (4)接口只能定义不能实现该方法

  (5)接口没有构造函数

  (6)接口中的方法和实现它的类默认都是public类型的

2. 抽象类:

  (1)对抽象类的使用是通过关键字extends2)不能被实例化,可以定义子类必须实现的方法

  (3)子类必须定义父类中的所有抽象方法,这些方法的访问控制必须和父类中一样(或者更为宽松)

  (4)如一个类中有一个抽象方法,则该类必须定义为抽象类

  (5)抽象类可以有构造函数

  (6)抽象类中的方法可以使用private,protected,public来修饰。

  (7)一个类可以同时实现多个接口,但一个类只能继承于一个抽象类。

3. Final/方法:

  (1final类不能被继承

  (2final方法不能被重写

4. Static/方法:

  (1)可以不实例化类而直接访问

  (2)静态属性不可以由对象通过->操作符来访问,::方式调用
  

写出乘法表的算法


1.九九乘法表 for 实现:

for ($i=1; $i < 10; $i++) {  

	for ($j=1; $j <= $i ; $j++) { 
        
        if($i > 4 && $j == 2){
            echo $j .' * '. $i .' = '. $i*$j . '&nbsp;&nbsp;&nbsp;';
        }else{
            echo $j .' * '. $i .' = '. $i*$j . '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
        }

	}

	echo '<br><br>';

}


2.九九乘法表 while 实现:

$m = 1;

while($m<10){   

    $n = 1;  

    while($n<=$m){      

        echo $m.'*'.$n.'='.$m*$n.'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';       

        $n++;      

    }      

    echo '<br><br>';       

    $m++;

}

echo 、print_r 、print 、var_dump 区别


echoPHP语句, print()print_r() 是函数,语句没有返回值,函数可以有返回值(即便没有用)

print() 只能打印出简单类型变量的值(int,string)

print_r() 可以打印出复杂类型变量的值(如数组,对象)

echo 输出一个或者多个字符串

print():是函数,有返回值

print_r():能打印数组,对象

var_dump():能打印对象数组,并且带数据类型


session 和 cookie 的区别


session:储存用户访问的全局唯一变量,存储在服务器上的php指定的目录中的(session_dir)的位置进行的存放

cookie:用来存储连续訪問一个頁面时所使用,是存储在客户端,对于Cookie来说是存储在用户WIN的Temp目录中的。

两者都可通过时间来设置时间长短


用PHP写出显示客户端IP与服务器IP的代码


客户端:$_SERVER["REMOTE_ADDR"];

服务器:$_SERVER["SERVER_ADDR"];


isset() 、empty() 的区别


isset():

若变量不存在则返回 FALSE

若变量存在且其值为NULL,也返回 FALSE

若变量存在且值不为NULL,则返回 TURE

同时检查多个变量时,每个单项都符合上一条要求时才返回 TRUE,否则结果为 FALSE

 

empty():

若变量不存在则返回 TRUE

若变量存在且其值为""0"0"NULL、、FALSEarray()var $var; 以及没有任何属性的对象,则返回 TURE

若变量存在且值不为""0"0"NULL、、FALSEarray()var $var; 以及没有任何属性的对象,则返回 FALSE


常见的负载均衡方案

均衡负载类型讲解:https://editor.csdn.net/md/?articleId=119530744


1.基于DNS的负载均衡

2.基于四层交换技术的负载均衡

3.基于七层交换技术的负载均衡

4.四层+七层负载结合方案


MySQL 事务的四大特性


一般来说,事务是必须满足4个条件(ACID):

  1.原子性(Atomicity,或称不可分割性)
  2.一致性(Consistency)
  3.隔离性(Isolation,又称独立性)
  4.持久性(Durability)。
  
原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。
  	   事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
	   这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
	   事务隔离级别,分为:
	   1.读未提交(Read uncommitted)
	   2.读提交(read committed)
	   3.可重复读(repeatable read)
	   4.串行化(Serializable)。

持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。


MySQL 事务隔离级别


一、读未提交(RU)

MySQL 事务隔离其实是依靠锁来实现的,加锁自然会带来性能的损失。而读未提交隔离级别是不加锁的,所以它的性能是最好的,没有加锁、解锁带来的性能开销。但有利就有弊,这基本上就相当于裸奔啊,所以它连脏读的问题都没办法解决。任何事务对数据的修改都会第一时间暴露给其他事务,即使事务还没有提交。


二、读提交(RC)

既然读未提交没办法解决脏数据问题,那么就有了读提交。读提交就是一个事务只能读到其他事务已经提交过的数据,也就是其他事务调用 commit 命令之后的数据。那脏数据问题就迎刃而解了。


三、可重复读(RR)

可重复是对比不可重复而言的,不可重复读是指同一事务不同时刻读到的数据值可能不一致。而可重复读是指事务不会读到其他事务对已有数据的修改,即使其他事务已提交;也就是说,事务开始时读到的已有数据是什么,在事务提交前的任意时刻,这些数据的值都是一样的。但是对于其他事务新插入的数据是可以读到的,这就引发了幻读的问题。

四、串行化

串行化是 4 种事务隔离级别中隔离效果最好的,解决了脏读、可重复读、幻读的问题,但是效果最差,它将事务的执行变为顺序执行,与其他三个隔离级别相比,它就是相当于单线程,后一个事务的执行必须等待前一个事务结束才能执行。

隔离级别说明与更换级别:https://blog.csdn.net/qq_39408664/article/details/119004699

读取未提交(脏读问题)与读取已提交(不可重复读问题):https://blog.csdn.net/qq_39408664/article/details/119025393

可重复读(幻读问题)与串行化说明:https://blog.csdn.net/qq_39408664/article/details/119037440


线程和进程


进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。

线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。
	 线程也被称为轻量级进程。一个程序至少一个进程,一个进程至少一个线程。


**进程线程的区别:**

地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。

资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之间的资源是独立的。

 
一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。
同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程

 执行过程:每个独立的进程程有一个程序运行的入口、顺序执行序列和程序入口。
 但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

线程是处理器调度的基本单位,但是进程不是。

两者均可并发执行。

 
**优缺点:**

线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。

进程执行开销大,但是能够很好的进行资源管理和保护。进程可以跨机器前移。

 
 **何时使用多进程,何时使用多线程?**

对资源的管理和保护要求高,不限制开销和效率时,使用多进程。

要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。


谈谈数据库优化


从sql优化方面来讲:

1. 不要返回任何用不到的字段

2. 尽量避免全表扫描,在where和order by涉及的字段上加索引

3. 尽量避免在 where 子句中对字段进行 null 值判断,会使索引失效

4. 尽量避免在 where 子句中使用 !=<> 操作符,会使索引失效

5. 尽量避免在 where 子句中使用 or 来连接条件,会使索引失效

6. 尽量避免在where子句中对字段进行函数操作,会使索引失效


从表优化方面来讲:

1. 可以水平分表,将一张表拆成多张结构一样的表,用表名区分

2. 可以垂直分表,将表中较大的字段拆分到另一张表中,该表与原表是一对一的关系


从库优化方面来讲:

可以将数据库分为主从库,主库用来写数据,多个从库用来读数据,主库与从库之间通过某种机制实现数据同步


什么是sql注入?怎么解决?


sql注入指web应用程序对用户输入数据的合法性没有判断或过滤不严格,
	进而导致攻击者可以在事先定义的sql语句上添加额外的sql语句,
	以此来实现欺骗数据库从而执行非授权的任意查询。

解决方案:

1. 对用户的输入进行校验,可以通过正则表达或限制长度

2. 使用参数化的sql而不是使用动态拼装的sql

3. 避免直接响应数据库异常信息,最好自定义错误信息进行包装

4. 限制数据库权限


如何分析sql?explain有哪些常用字段?


使用explain关键字可以模拟优化器执行SQL语句,分析查询语句或是结构的性能瓶颈

字段解释:

1. id:表的读取顺序,id相同,读取顺序从上到下,id不同,值越大则优先级越高。

2. select_type:查询类型;simple表示简单查询,不包含子查询或联合查询。

3. table:表示这一行的数据是关于哪张表的。 

4. type:表示的是表的连接类型。

5. possible_keys:列支出mysql能使用哪个索引在该表中找到行。

6. key:表示查询实际应用到的索引。

7. key_len:表示mysql选择的索引字段按字节计算的长度。

8. ref:表示使用哪个列或常数与索引一起来查询记录。

9. rows:显示mysql表中进行查询时必须检查的行数。

10.filtered:表示返回结果的行数占需读取行数的百分比,列的值越大越好。

11.Extra:显示mysql在处理查询时的详细信息 或者理解为 额外的信息说明。


redis有哪几种数据类型?适合什么场景下使用?


1. string(set、get)适用于最简单的key-value存储。

2. hash(hget、hset、hgetall)假设有多个用户信息,key为用户id,将用户信息序列化作为value存储。

3. list(lpush、lpop、rpush、rpop,有序可重复)适用于关注列表、粉丝列表、轻量级消息队列等。

4. set(sadd、srem、spop,无序不可重复)适用于不重复的列表。

5. zset(zadd、zrem,有序不可重复)适用于用户积分排行榜等。


redis 和 memcache 有什么区别?


1. memcache可以缓存图片、视频等,而redis不行。

2. redis不仅支持简单的key-value数据类型,还提供了hash、list、set等数据结构。

3. redis还可以将数据持久化到磁盘上,memcache只能将数据存储于内存中。

4. 当缓存挂掉后,memcache数据无法恢复,redis可以通过aof策略根据操作日志恢复数据。


什么是雪崩?如何解决?


在高并发下,大量缓存key在同一时间失效,大量的请求直接落在数据库上,导致数据库压力过大宕机

解决方案:

1. 设置redis集群+哨兵模式的高可用,一旦redis出现宕机,可立即由其它机器顶替

2. 随机设置key的失效时间,避免大量key同时失效


什么是穿透?如何解决?


redis缓存和数据库中没有相关数据,请求无法进行拦截,直接被穿透到数据库,导致数据库压力过大宕机

解决方案:

1. 将不存在的数据也缓存到redis中,设置一个较短的过期时间

2. 采用布隆过滤器,将所有可能的数据都hash到一个足够大的bitmap中,一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层查询系统的压力

3. 拉黑该ip地址


什么是击穿?如何解决?


某一个热点key在不停的扛着高并发,当这个key失效的一瞬间,持续的高并发就会直接访问数据库,导致数据库压力过大宕机

解决方案:

1. 热点数据设置永不过期

2. 实现互斥锁,在第一次查询时使用互斥锁锁住它,等第一个线程查询到了数据将数据存入缓存,之后的线程就可以直接走缓存


什么是面向对象?有哪些特征?


面向对象是一种对现实世界理解和抽象的方法,将需求要素转化为对象进行问题分析的思想

特征:封装、继承、多态


什么是类?


类是在对象之上的抽象,对象是类的具体化


opcache有什么作用?


opcache可以将php脚本预编译的字节码存放在内存中来避免每次加载和解析php脚本的开销,解析器可以直接从内中读取已缓存的字节码,从而提高php的执行效率


PHP 有哪些常用函数?


1.数组:

count($array,$model); 统计数组元素个数

in_array($element,$array); 判断数组中是否存在某元素

array_merge($arr1,$arr2); 合并两个数组

implode($str,$array); 将数组中的元素用字符拼接成一个字符串

json_encode($array); 将数组转化为json字符串


2.字符串:

strlen(); 字符长度

substr($str,$start,$length); 截取字符串

str_replace($find,$replace,$str); 替换字符串

explode($s,$str); 分割字符串为数组


3.时间:

time(); 返回1970到现在的秒数

date($format,$timestap); 将时间戳转化为特定格式的字符串


for和foreach有什么区别?


1. 在固定长度或长度不需要计算的时候for的效率比foreach2. 在不确定长度或计算长度损耗性能的时候用foreach比较方便


tcp有哪五层协议?


应用层、传输层、网络层、数据链路层、物理层


谈谈tcp三次握手?


1. 客户端向服务端发送一个连接请求报文段,其中SYN设置为1,并随即选择一个起始序号seq=x

2. 服务端收到请求报文段后,向客户端发送一个确认报文段,其中SYNACK设置为1,确认号字段为x+1,并生成一个起始序号seq=y

3. 当客户端收到确认报文段后,还要再向服务端一个确认报文段,其中ACK设置为1,确认号字段为y+1,序号字段为x+1

注:SYN为同步序号,ACK为确认序号标志


http和https有什么区别?


1. http是不安全的,https是安全的

2. http的标准端口是80,https的标准端口是443

3. http无需认证证书,https需要认证证书


HTTP状态码


常见的状态码:

200 - 请求成功

301 - 资源(网页等)被永久转移到其它URL

404 - 请求的资源(网页等)不存在

500 - 内部服务器错误


分类		描述

1**		信息,服务器收到请求,需要请求者继续执行操作

2**		成功,操作被成功接收并处理

3**		重定向,需要进一步的操作以完成请求

4**		客户端错误,请求包含语法错误或无法完成请求

5**		服务器错误,服务器在处理请求的过程中发生了错误

状态码详情:https://www.runoob.com/http/http-status-codes.html


浏览器通过URL访问的原理


1.键盘或触屏输入URL并回车确认

2.URL解析/DNS解析查找域名IP地址

3.网络连接发起HTTP请求

4.HTTP报文传输过程

5.服务器接收数据

6.服务器响应请求/MVC

7.服务器返回数据

8.客户端接收数据

9.浏览器加载/渲染页面

10.打印绘制输出


什么是csrf攻击?如何预防?


跨站请求伪造,利用浏览器的cookie和服务器的session盗取用户身份

解决方案:

1. 向表单添加字段标记,比如uuid令牌

2. 添加验证码

3.检查请求头中的referer字段


什么是xss攻击?如何预防?


跨站脚本攻击,攻击者会在web页面插入一些恶意的javascript代码;
当用户浏览该页面时,嵌入到页面中的javascipt就会执行,以达到恶意攻击用户的目的。

解决方案:

1. 设置httponly,使js脚本无法读取cookie信息。

2. 同时在js和服务端上检查用户输入的合法性。

3. 在变量输出到html页面时,使用编码或转义。


接口签名应如何设计?


1. 接口调用方和接口提供方约定好统一的参数加密方法,如md5加密

2. 接口调用方将加密后的_sign放在参数中

3. 接口调用方将时间戳放在参数中保证请求的唯一性和有效性


谈谈elasticsearch?


elasticsearch是一种搜索引擎,简称为:es,本质是一个java服务器,使用前需要提前将数据录入才能够使用搜索功能

常用查询字段:match、match_phrase、multi_match、bool

常用分词器:standard analyzer(按词切分,小写处理)、simple analyzer(按照非字母切分,小写处理)、whitespace analyzer(按空格切分,不转小写)


为什么Redis是单线程的


因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。
既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。


Redis单线程的优劣势


1.单进程单线程优势
  1) 代码更清晰,处理逻辑更简单
  2) 不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
  3) 不存在多进程或者多线程导致的切换而消耗CPU
 
2.单进程单线程弊端
  无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善;
 

PHP是单线程还是多线程?

PHP 从设计之初到流行起来都没有出现明显需要用多线程才能解决的需求。某些需要用到多线程的地方也有相应的解决方案和替代方案。多线程并不总是比单线程优,多线程可能会引入其他问题:例如:两个线程同时调用一个类里的同一个方法时,可能出现死锁的情况。


你可以这样理解 对应一个客户的一个页面请求处理的php 是单线程处理的, 这样一来就可以自上而下的去编辑/理解代码中的业务逻辑了, 但是 php 可以同时开很多线程来处理 很多用户请求的同一个PHP , 所以 php 也可以看成是"多线程"的。


MySQL 索引什么时候失效


1. 如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引

2. like 模糊查询以%开头

3. 如果mysql估计使用全表扫描要比使用索引快,则不使用索引

4. 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引

5. 对于组合索引,不按照最左匹配原则


PHP 的常用算法

冒泡排序法 、选择排序法 、插入排序 、快速排序算法

一、冒泡排序法

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,依次比较两个元素,如果他们的顺序错误就把他们交换过来。

走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越来越小的元素会经由交换慢慢"浮"到数列的顶端。

步骤:

①:比较相邻的元素。如果第一个比第二个大,就交换他们两个

②:对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

③:针对所有的元素重复以上的步骤,除了最有一个

④:持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

具体代码:


$arr=array(1,43,54,62,21,66,32,78,36,76,39);

print_r(bubbleSort($arr));

function bubbleSort($arr){

    $len = count($arr);

    //该层循环控制 需要冒泡的轮数

    for ($i=1; $i<$len; $i++) {

        //该层循环用来控制每轮 冒出一个数 需要比较的次数

        for ($k=0; $k<$len-$i; $k++) {

            if($arr[$k] > $arr[$k+1]) {

                $tmp = $arr[$k+1]; // 声明一个临时变量

                $arr[$k+1] = $arr[$k];

                $arr[$k] = $tmp;

            }

        }

    }

    return $arr;

}


二、选择排序法

选择排序是一种简单直观的排序算法。它的工作原理如下:首先是在末排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从 剩余未排序元素中继续寻找最小元素。然后放到排序序列末尾。以此类推,直到所有元素均排序完成。

具体代码:


$arr=array(1,43,54,62,21,66,32,78,36,76,39);

print_r(select_sort($arr));

//实现思路 双重循环完成,外层控制轮数,当前的最小值。内层 控制的比较次数
 function select_sort($arr) {

    //$i 当前最小值的位置, 需要参与比较的元素
    for($i=0, $len=count($arr); $i<$len-1; $i++) {

        //先假设最小的值的位置
        $p = $i;

        //$j 当前都需要和哪些元素比较,$i 后边的。
        for($j=$i+1; $j<$len; $j++) {

            //$arr[$p] 是 当前已知的最小值
            if($arr[$p] > $arr[$j]) {

                //比较,发现更小的,记录下最小值的位置;并且在下次比较时,应该采用已知的最小值进行比较。
                $p = $j;

            }

        }

        //已经确定了当前的最小值的位置,保存到$p中。
        //如果发现 最小值的位置与当前假设的位置$i不同,则位置互换即可
        if($p != $i) {

            $tmp = $arr[$p];

            $arr[$p] = $arr[$i];

            $arr[$i] = $tmp;

        }

    }

    //返回最终结果

    return $arr;

}


三、插入排序

插入排序的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在一排序序列中从后向前扫描,找到相应的位置并插入。

插入排序在实现上,通常采用in-place排序(既只需用到O(1)的额外空间的排序),因而在从后面向前扫描过程中,需要反复把已排完元素逐步向后挪位,为最新元素提供插入空间。

步骤:

①从第一个元素开始,该元素可以认为已经被排序

②取出下一个元素,在已经排序的元素序列中从后向前扫描

③如果该元素(已排序)大于新元素,将该元素移到下一个位置

④重复步骤③,直到找打已排序的元素小于或者等于新元素的位置

⑤将新元素插入到该位置中

⑥重复步骤②

具体代码:


$arr=array(1,43,54,62,21,66,32,78,36,76,39);

print_r(insert_sort($arr));

function insert_sort($arr){

    $len=count($arr);

    for($i=1; $i<$len; $i++) {

        //获得当前需要比较的元素值。
        $tmp = $arr[$i];

        //内层循环控制 比较 并 插入
        for($j=$i-1; $j>=0; $j--) {

            //$arr[$i];//需要插入的元素; $arr[$j];//需要比较的元素
            if($tmp < $arr[$j]) {

                //发现插入的元素要小,交换位置
                //将后边的元素与前面的元素互换
                $arr[$j+1] = $arr[$j];

                //将前面的数设置为 当前需要交换的数
                $arr[$j] = $tmp;

            } else {

                //如果碰到不需要移动的元素
                //由于是已经排序好是数组,则前面的就不需要再次比较了。

                break;

            }

        }

    }

    //将这个元素 插入到已经排序好的序列内。
    //返回

    return $arr;

}


四、快速排序算法

快速排序是由东尼·霍尔发展的一种排序算法。在平均状况下 ,排序n个项目要O(n log n)次比较。

在最坏状况下则需要O(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他O(n log n)算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地实现出来,且大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方之可能性。

步骤:

①从数列中挑出一个元素,称为‘基准’

②重复排序数列,所有元素比基准值小的摆放到基准前面,所有元素比基准大的摆放到基准后面(相同的数可以到任意一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作

③递归地把小于基准值元素的子数列和大于基准值元素的子数列排序

具体代码:


$arr=array(1,43,54,62,21,66,32,78,36,76,39);

print_r(quick_sort($arr));

function quick_sort($arr){

     //判断参数是否是一个数组
     if(!is_array($arr)) return false;

     //递归出口:数组长度为1,直接返回数组
     $length = count($arr);

     if($length<=1) return $arr;

     //数组元素有多个,则定义两个空数组
     $left = $right = array();

    //使用for循环进行遍历,把第一个元素当做比较的对象
    for($i=1; $i<$length; $i++){

        //判断当前元素的大小
        if($arr[$i]<$arr[0]){

            $left[]=$arr[$i];

        }else{

            $right[]=$arr[$i];

        }

    }

    //递归调用
    $left=quick_sort($left);

    $right=quick_sort($right);

    //将所有的结果合并
    return array_merge($left,array($arr[0]),$right);

}


常见的PHP框架

ThinkPHP 、yii 、Laravel 、Zend Framework 、Yaf


如何理解ThinkPHP框架中的单一入口文件?

:ThinkPHP采用单一入口模式进行项目部署和访问,无论完成什么功能,一个项目都有一个统一(但不一定是唯一)的入口。应该说,所有项目都是从入口文件开始的,并且所有的项目的入口文件是类似的,入口文件中主要包括:

定义框架路径、项目路径和项目名称(可选)

定义调试模式和运行模式的相关常量(可选)

载入框架入口文件(必须)


ThinkPHP如何防止SQL注入?(理解)

(1)查询条件尽量使用数组方式,这是更为安全的方式;

(2)如果不得已必须使用字符串查询条件,使用预处理机制;

(3)开启数据字段类型验证,可以对数值数据类型做强制转换;(3.1版本开始已经强制进行字段类型验证了)

(4)使用自动验证和自动完成机制进行针对应用的自定义过滤;

(5)使用字段类型检查、自动验证和自动完成机制等避免恶意数据的输入。


ThinkPHP中的MVC分层是什么?(理解)

MVC 是一种将应用程序的逻辑层和表现层进行分离的方法。ThinkPHP 也是基于MVC设计模式的

MVC只是一个抽象的概念,并没有特别明确的规定,ThinkPHP中的MVC分层大致体现在:

模型(M):模型的定义由Model类来完成。

控制器(C):应用控制器(核心控制器App类)和Action控制器都承担了控制器的角色,Action控制器完成业务过程控制,而应用控制器负责调度控制。

视图(V):由View类和模板文件组成,模板做到了100%分离,可以独立预览和制作。

但实际上,ThinkPHP并不依赖M或者V ,也就是说没有模型或者视图也一样可以工作。甚至也不依赖C,这是因为ThinkPHP在Action之上还有一个总控制器,即App控制器,负责应用的总调度。在没有C的情况下,必然存在视图V,否则就不再是一个完整的应用。

总而言之,ThinkPHP的MVC模式只是提供了一种敏捷开发的手段,而不是拘泥于MVC本身。


如何理解 ThinkPHP架构(核心 + 行为 + 驱动)中的行为?

TP官方简称为:CBD

核心(Core):就是框架的核心代码,不可缺少的东西,TP本身是基于MVC思想开发的框架。

行为(Behavior) :行为在新版ThinkPHP的架构里面起着举足轻重的作用,在系统核心之上,设置了很多标签扩展位,而每个标签位置可以依次执行各自的独立行为。行为扩展就因此而诞生了,而且很多系统功能也是通过内置的行为扩展完成的,所有行为扩展都是可替换和增加的,由此形成了底层框架可组装的基础。

驱动( Driver ):数据库驱动、缓存驱动、标签库驱动和模板引擎驱动,以及外置的类扩展。

框架,即framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。


ThinkPHP 与 Laravel 框架的区别

一、渲染模版方式的不同

在Laravel框架里,使用return view()来渲染模版;而ThinkPHP里则使用了$this->display()的方式渲染模版。

二、POST提交数据的方式

Laravel在提交表单时需要在表单中加入下面的标签信息来防止跨域攻击,而TP不会。
<input type="hidden" name="_token" value="{{csrf_token()}}" />

三、路由

Laravel必须先定义,再使用,路由文件为routes.php;TP在配置文件中开启路由后,路由格式是:’路由表达式’ => ‘路由地址和参数’(使用路由的前提是URL支持phthinfo并且开启路由),路由可以使URL更符合SEO。

四、中间件

Laravel特点,可以实现访问前后的处理,例如请求和返回,权限认证等;

TP5版本中,5.1支持中间件,5.0不支持,但是在TP6版本中则直接支持中间件,跟Laravel的几乎相同。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值