PHP 控制结构
控制结构是通过条件与逻辑,控制代码的执行顺序。
比如:商城的服务员,培训的时候,学两句话
第一句话:先生您好
第二句话:女士您好
/**
* 编程不难,编程就是说话(请大家记住燕十八老师这句话)
* 我们能描述一件事情,我们就能写程序
* 把事情想清楚,编程就是一个翻译而已
*
* 如果 -> if
* 否则如果 -> else if
* 否则 -> else
* 如果感觉没思路,是因为我们连事件怎么发展都没想清楚
*
* *.php?gender=男
* 输出:先生,您好
*
* *.php?gender=女
* 输出:女士,您好
*
* *.php?gender=*(其它)
* 输出:春春,我喜欢你
*
* *.php
* 输出:没有传值
*
*
* 代码说明:
* 1. 先用isset判断GET有没有传值
* 这样不会出现提示信息 Notice: Undefined variable……
* 2. 如果有传值,再执行里面的判断语言
* 3. 如果没有传值,就提示"没有传值"
*
*/
if(isset($_GET['gender'])){
$gender = $_GET['gender'];
if($gender == '男'){
echo '先生,您好';
}else if($gender == '女'){
echo '女士,您好';
}else{
echo '春春,我喜欢你';
}
}else{
echo '没有传值';
}上面的代码,已经用上了流程控制,即我们学的控制结构。
有几种控制结构?
1. 顺序
2. 分支
3. 循环
这三种控制结构,所有语言都一样。
几十年来,为什么没有发展出第四种类控制结构?
有一位计算机科学家写过一篇论文,这3种控制结构对于编程模型足够了。
先看最简单的顺序结构
一、顺序结构
顺序结构,就是语句按照我们书写的顺序,从前到后顺序执行。
echo 'a: 8点了 <br/>'; echo 'b: 来YY88354001频道上课了 <br/>'; echo 'c: 我听懂了 <br/>'; echo 'd: 我开始写博客了'; /** * 非常自然,打印出来的的顺序是a, b, c, d * 按我们书写的顺序,依次执行 * 这就是"顺序结构" * */
顺序结构没什么问题,下面看分支结构
二、分支结构
分支结构
顾名思义,分支就像一条大路,走到了分叉口,该选择一个岔口走下去
1、先看最简单的,单路分支 —— if
/**
* 1. if判断括号内的表达式($age >= 18),最终是要转成布尔值的
* 2. 布尔值只有两种情况,真或假
* 如果为真:就走花括号里面的代码段
* 如果是非真:就不走花括号里面的代码段
* 也就是说if花括号里面的代码只有两种情况,要么执行,要么不执行
* 3. ($age >= 18)括号中的表达式,如果为真就执行
*/
$age = 18;
if($age >= 18){
echo '已';
echo '成';
echo '年';
}2、双路分支结构 —— if/else
/**
* if(expression)表达式
*
* if为真,则代码段1执行
* if为假,则代码段2执行
* if/ else中的两个代码段,必有且只有一段执行
*
*/
$yaer = 2012;
$birth = 1985;
$age = $yaer - $birth;
if($age > 28){
echo '你是中老年'; // 代码段1
}else{
echo '你是有为青年'; // 代码段2
}3、多路分支
$age = 304;
if($age <= 16){
echo '少年';
}else if($age > 16 && $age <= 28){
echo '少年';
}else if($age > 28 && $age <= 300){
echo '中老年';
}else{
echo '动物园的乌龟跑了';
}4、多路分组结构 —— switch
先用 if else 实现一个功能,根据输入的值,显示对应的星期几
// $day = 2; // 1, 2, 3, 4, 5, 6, 7
$day = rand(1, 8); // 用随机数
echo $day,'<br/>';
if($day == 1){
echo '星期一';
}else if($day == 2){
echo '星期二';
}else if($day == 3){
echo '星期三';
}else if($day == 4){
echo '星期四';
}else if($day == 5){
echo '星期五';
}else if($day == 6){
echo '星期六';
}else if($day == 7){
echo '星期日';
}else{
echo '你来自火星';
}对于一个变量的值,有多种可能性,用 if/else if来比较,当然是可以的
但是,有一直更简单的switch分支 来替换 if/else if
$day = 3;
switch($day){
case 1:
echo '星期一 <br/>';
case 2:
echo '星期二 <br/>';
case 3:
echo '星期三 <br/>';
case 4:
echo '星期四 <br/>';
case 5:
echo '星期五 <br/>';
case 6:
echo '星期六 <br/>';
case 7:
echo '星期日 <br/>';
default:
echo '你来自火星';
}
/**
* 显示结果:
* 星期三
* 星期四
* 星期五
* 星期六
* 星期日
* 你来自火星
*
*
* $day = 3;
* 1. 从上到下找,找到"case 3"对上了
* 2. 对上了后,下面的语句都去执行
*/如果想合理的只执行"星期三",要加break(break有破坏的意思)
switch($day){
case 1:
echo '星期一 <br/>';
break;
case 2:
echo '星期二 <br/>';
break;
case 3:
echo '星期三 <br/>';
break;
case 4:
echo '星期四 <br/>';
break;
case 5:
echo '星期五 <br/>';
break;
case 6:
echo '星期六 <br/>';
break;
case 7:
echo '星期日 <br/>';
break;
default:
echo '你来自火星';
}if/else if 与 switch 相比,各适用于什么样的场合?
- switch case只能判断某变量,是否于指定的值相等,比如指定的值 与1, 2, 3, 4……比较。
但是switch case不能用来判断范围。
- 而if /else if可以用来判断范围,甚至更复杂的判断表达式都可以,而case却只能提供一个准确的值,和变量做相等(==)的比较。
如果需要和几个确认的值比较是否相等,适合用switch
三、循环结构
编程语言中,一般都有这几种循环:
for循环
while循环
do while循环
1、先从简单的while循环开始
看一个生活中的例子:
1). 假设某人 "心里强度" 是100
3). 每打他一拳,心里强度减少1
3). 当 心里强度 < 30,就能把他打服气
4). 所以我们要不断的打他
/**
* $hit + $hard的意思:
* 1. $hit + $hard 相加,相当于打了一拳(心里强度减小 1)
* 2. $hard = $hit + $hard 相加后减少的结果,再赋给$hit
* 3. $hard += $hit 可以这样简写
*
*/
$hard = 100;
$hit = -1;
$hard = $hit + $hard; // 负数相加,相当于打了一拳(心里强度减小 1)
if($hard >= 30){
echo $hard,'不服<br/>'; // 99不服
}else{
echo $hard,'服了<br/>';
}
$hard += $hit;
if($hard >= 30){
echo $hard,'不服<br/>'; // 98不服
}else{
echo $hard,'服了<br/>';
}
$hard += $hit;
if($hard >= 30){
echo $hard,'不服<br/>'; // 97不服
}else{
echo $hard,'服了<br/>';
}
/**
* 只要不服,接着打,直到服了为止。
*
* $hard += $hit;
* if($hard >= 30){
* echo $hard,'不服<br/>';
* }else{
* echo $hard,'服了<br/>';
* }
*
* 即,上面的代码段,重复执行,直到"$hard < 30"
*
*/用while循环来做
/**
* while(表达式){
* 语句(代码段);
* }
*
* while循环的意思是:
* 1. 判断表达式是否为真,如果为真,则执行语句
* 2. 执行完语句之后,再回到while(表达式)开始处,去判断"表达式"是否为真
*
* 表达式如果为真,则执行语句
* …………
* …………
*
* 3. 表达式如果为假,本次循环就结束
*
*/
$hard = 100;
$hit = -1;
while($hard >= 30){
$hard += $hit;
if($hard >= 30){
echo $hard,'不服<br/>';
}else{
echo $hard,'服了<br/>';
}
}
echo '"hard == 29"时候,"hard > 30"不成立,循环结束,来到这儿了';有没有刚一上来就不满足条件,表达式就是假,也就是说循环里面的语句,一次都不执行,这种情况,有没有可能?
/**
* $hard = 20;
* 心里素质直接是20,软蛋一个,不用打
* 运行,页面空空,一次没执行
* 因为 if($hard >= 30) 因为括号中的表达式,刚开始就为假
*
*/
$hard = 20; // 软蛋一个,不用打了
$hit = -1;
while($hard >= 30){
$hard += $hit;
if($hard >= 30){
echo $hard,'不服<br/>';
}else{
echo $hard,'服了<br/>';
}
}如果碰到下面的情况,将会怎么样?
while(true){
echo '哈哈<br/>';
}
/**
* 语句是"死循环"
* 因为无论执行多少次,true始终是true,将永远执行下去
* 小心死机!
*
*/2、do while循环
思考下面这种情况:
某看守所,新进去的人(专业叫:新收)上去就得挨顿打,
不管是硬、还是软,都要经历入学考试,上来总要打一次,
转成程序语言:不管你一开始开始,服不服,总得先打一顿,怎么写?
$hard = 20;
$hit = -1;
do{
$hard += $hit; // 1. 先打一次
if($hard >= 30){ // 2. 打了之后再做判断
echo $hard,'不服<br/>';
}else{
echo $hard,'服了<br/>';
}
}while($hard >= 30); // 3. 判断的条件还是一样
/**
* do while循环
*
* do是执行的意思
* 上来先执行一下语句,然后(打了之后)再做判断
* 所以do/while,至少执行一次
* 输出:19服了
*
*/while循环:
就像去快餐店吃饭,先付钱
没有钱,服务员说:请走人
do/while循环:
先吃饭,再判断有没有钱
有可能没钱,吃了霸王餐
做一个面试题:
写一个程序打印1到100的数字。
但是遇到数字为3的倍数的时候,打印"Fizz"代替数字
5的倍数用"Buzz"代替
既是3的倍数、又是5的倍数打印"abced"
$num = 1;
while($num <= 100){
if($num%3 == 0 && $num%5 == 0){
echo $num,'-','abcde<br>';
}else if($num%3 == 0){
echo $num,'-','Fizz<br>';
}else if($num%5 == 0){
echo $num,'-','Buzz<br>';
}else{
echo $num,'<br>';
}
$num ++;
}再简化一点
$num = 0;
while(++$num <= 100){
if($num%3 == 0 && $num%5 == 0){
echo $num,'-','abcde<br>';
}else if($num%3 == 0){
echo $num,'-','Fizz<br>';
}else if($num%5 == 0){
echo $num,'-','Buzz<br>';
}else{
echo $num,'<br>';
}
}3、for循环
/**
* 生活中的场景:
* 富一代:儿子,给你N万元,断绝父子关系,爱干吗干吗去
* 富二代:当天就去打游戏,打完游戏后,钱就少了一些
* 第二天,数数钱,还够再打游戏的,再去打了一天
* 循环……
* ……
* 直到某一天,钱不够了打游戏了,结束
*
*
* 分析要素:
* 1. 富一代,给钱,初始化动作,只执行一次
* 2. 富二代,判断钱,够不够打游戏,如果钱够
* 3. 打游戏,打完游戏
* 4. 钱减少
* 第二天,再判断钱够不够打游戏,如果钱够,打游戏,钱减少……循环
*
*
* [1]初始化的动作只执行一次,
* 然后[2]判断动作
* 然后[3]执行动作
* 然后[4]减少钱的动作
*
* for(初始条件[1]; 判断条件[2]; 减少钱[4]){
* 执行语句[3]
* }
*
* 执行过程:
* 语句[1]先执行一次,然后[2][3][4]循环,直到语句[2]判断不成立,跳出循环
*
*/
for($i = 10; $i >= 1; $i--){
echo $i,'<br/>';
}
// echo $i; // 在循环外面,打印变量$i输出0扩展一下for循环,同时循环两个数
打印这样一个效果:
5 1
4 2
3 3
2 4
1 5
我自己练习写的
$j = 1;
for($i = 5; $i >= 1; $i--){
echo $i,' ',$j++,'<br/>';
}十八哥教程的写法,很有想象力,让我彻底了解了for循环
1). $j=1; 只执行一次,是只执一次,
但是意味着未必,只能给一个变量赋值,再声明一个$j=1;
2). 在$--的时候,再来一个$j++
for($i=5,$j=1; $i >= 1; $i--,$j++){
echo $i,' ',$j,'<br/>';
}百钱买百鸡的问题
《张丘建算经》作者北魏人,书中最后一道题堪称亮点,
通常也被称为“百钱买百鸡”代数的角度上讲就是“不定向方程”
一只公鸡:5元
一只母鸡:3元
三只小鸡:1元
用100块钱,正好买回来100只鸡
问:公鸡、母鸡、小鸡各多少只?
/**
* 循环暴力运算
*
* 思路:
* 公鸡 1-100只
* 母鸡 1-100只
* 小鸡 1-100只
* 暴力组合
*
* 满足两个条件
* $g + $m + $x) == 100 && (5*$g + 3*$m + $x/3) == 100
* 公鸡数 + 母鸡数 + 小鸡数 = 100
* 并且
* 公鸡数价格 + 母鸡数价格 + 小鸡数价格 = 100
*
*/
for($g = 1; $g <= 100; $g++){
for($m = 1; $m <= 100; $m++){
for($x = 1; $x <= 100; $x++){
if(($g + $m + $x) == 100 && (5*$g + 3*$m + $x/3) == 100){
echo '公鸡',$g, ' 母鸡',$m, ' 小鸡',$x,'<br/>';
}
}
}
}
/**
* 打印结果:
* 公鸡4 母鸡18 小鸡78
* 公鸡8 母鸡11 小鸡81
* 公鸡12 母鸡4 小鸡84
*
*/思考:
上面的for循环,虽然算出来了结果,但效率很低
因为,如果运气非常差
要运行 100 * 100 * 100 = 100万次
可以优化一下:
因为公鸡 + 母鸡 + 小鸡共100只
因此 $x = 100 - $g - $m; 就是小鸡的数量
/**
* for循环变成两层,去掉最里面的小鸡的for循环
* 小鸡是直接算出来的
* 这次优化掉了一层for循环,运气最差,执行100 * 100次
*
*/
for($g = 1; $g <= 100; $g++){
for($m = 1; $m <= 100; $m++){
$x = 100 - $g - $m;
if(($g + $m + $x) == 100 && (5*$g + 3*$m + $x/3) == 100){
echo '公鸡',$g, ' 母鸡',$m, ' 小鸡',$x,'<br/>';
}
}
}
/**
* 打印结果:
* 公鸡4 母鸡18 小鸡78
* 公鸡8 母鸡11 小鸡81
* 公鸡12 母鸡4 小鸡84
*
*/继续优化:
因为公鸡每只5元,共100元,因此公鸡不可能超过20只
因为母鸡每只3元,共100元,因此母鸡不可能超过33只
for($g = 1; $g <= 20; $g++){
for($m = 1; $m <= 33; $m++){
$x = 100 - $g - $m;
if(($g + $m + $x) == 100 && (5*$g + 3*$m + $x/3) == 100){
echo '公鸡',$g, ' 母鸡',$m, ' 小鸡',$x,'<br/>';
}
}
}
// 此时利用边界条件,优化了效率,最多运行 20 * 33 次复习
一、顺序结构
按顺序执行
二、分支结构
1、if 单路分支
2、if /else 双路分支
双路分支中,if/else中的2个代码段,必有且只有一段被执行
3、if /else if /else if .../ else 多路分支
4、switch case 用来比较被判断的变量的多种可能值时
三、循环结构
1、whitch循环
whitch(表达式){
代码段
}
只要表达式为真,就执行代码段,
执行完代码段,再回去判断表达式,
为真……循环
直到表达式为假的时候,跳出循环
2、do whitch循环
do{
代码段
}whitch(表达式);
先执行代码段,再判断表达式的珍姐
do/while的重要特点,至少执行一次
3、for循环
for(表达式1; 表达式2; 表达式4){
循环体3;
}
1). 表达式1,先执行,且只执行一次
2). 然后来到,表达式2,判断一下,如果为假,结束for循环,如果为真,则执行循环体3
3). 循环体3执行完毕,再执行表达式4
再
表达式2判断,循环体3,表达式4,这三个来回循环
直到表达式2为假,for结束
四、break与continue
看两个场景,一个是警察抓罪犯的场景,一个是警察查身份证的场景
1、break
警察抓罪犯的场景:
已知,教室内,有一个犯罪分子,警察过来抓他(只有一个犯罪份子),
犯罪分子隐藏的很好,警察只好一个人、一个人的来检查,
看脚底板有一颗痣的是犯罪份子
张三 [检查]
李四 [检查]
王五 [检查]
罪犯 [抓罪犯的活动结束,后面的不用查了]
赵六
郑七
王八
/**
* break
* 如果"$i的值是6",break跳出循环,否则就打印$i
* 打印结果:
* 1
* 2
* 3
* 4
* 5
* break英语里有破坏的意思,
* 这里的意思是直接破坏,整个循环语句,不再往下执行了
*
*/
for($i = 1; $i < 10; $i++){
if($i == 6){
break;
}else{
echo $i,'<br/>';
}
}
// echo $i; // 循环外面$i的值是62、continue
continue在英语里有“继续”的意思
再来看一个场景:
这次警察查身份证,
已知,地铁口有10个人,警察来查身份证
也要一个人、一个人的来检查,
张三 [检查]
李四 [检查]
王五 (哎呀,这不是刚子吗?连我都不认识了。
邻居,警察认识王五,因此王五就不检查了,继续检查下一位 )
赵六 [检查]
郑七 [检查]
王八 [检查]
/**
* 当$i等于5的时候continue,直接跳过
* 打印结果:
* 1
* 2
* 3
* 4
*
* 6
* 7
* 8
* 9
*
* continue是继续的意思,是说继续下一次循环单元,"continue这次"可以跳过了
*
*/
for($i = 1; $i < 10; $i++){
if($i == 5){
echo '<br>';
continue;
}
echo $i,'<br/>';
}3、面试题
假设某人有100000现金,每经过路口需要进行一次交费。
交费规则:
当他现金大于50000时每次需要交5%
如果现金小于等于50000每次交5000
请写一程序计算,此人可以进过多少次路口?
// 这是我自己用while循环写的,只是为了练习
$station = 0; // 记录过收费口的次数
$money = 100000;
// echo var_dump($money > 5000);
while($money >= 5000){
if($money > 50000){
$tem = $money/100*5;
$money -= $tem;
$station ++;
}else{
$money -= 5000;
$station ++;
}
}
echo $money,'<br/>'; // 3767.497911553
echo $station; // 23下面是燕十八老师视频里教的代码,对for循环用的很透彻
/**
* 这是一个典型的for循环
*
* 分析:
* 给此人100000,初始条件
* 判断:钱至少 >= 50000才能过路口,判断条件($money >= 5000)
* 过一次路口,钱减少一次(执行体里面的代码)
*
* 1. $money = 100000 对应for循环的语句1,上来就执行一次
* 2. $money >= 5000 判断大于等于5000
* 3. 如果大于等于5000,就扣钱
* 怎么扣钱?
* 大于50000的时候,扣5%
* 小于50000的时候,扣5000
* 经过了这个执行体,就已经过了一次收费口了
* 4. 过了一次路口,记录一次
* 声明一个$num = 0,$num变量记录过路口的次数
* 过一次收费口,就$num++
* 5. 最后只需要打印$num就是过路口的次数
* echo $num;
*
*/
for($money = 100000,$num=0; $money >= 5000; $num++){
if($money > 50000){
$money *= 0.95; // 扣了5%,既原来的0.95倍
}else{
$money -= 5000;
}
}
echo $money,'<br/>'; // 3767.497911553
echo $num; // 23燕十八老师说,如果代码体现的不够清晰,再改造一下
for($money = 100000,$num=0; $money >= 5000; ){ // 第二个分号后竟然是空的,这样也是可以的
if($money > 50000){
$money *= 0.95; // 扣了5%,既原来的0.95倍
}else{
$money -= 5000;
}
$num++; // 只要到执行到这行,说明$money >= 5000判断成功
// 也扣了钱了,也过了收费站了,把过桥记录加1
echo '第 ',$num,' 次过收费站,剩余',$money,'元<br/>'; // 看每次过桥钱是怎么变化的
}
// echo $money,'<br/>'; // 3767.497911553
// echo $num; // 23
/******
打印结果:
第 1 次过收费站,剩余95000元
第 2 次过收费站,剩余90250元
第 3 次过收费站,剩余85737.5元
第 4 次过收费站,剩余81450.625元
第 5 次过收费站,剩余77378.09375元
第 6 次过收费站,剩余73509.1890625元
第 7 次过收费站,剩余69833.729609375元
第 8 次过收费站,剩余66342.043128906元
第 9 次过收费站,剩余63024.940972461元
第 10 次过收费站,剩余59873.693923838元
第 11 次过收费站,剩余56880.009227646元
第 12 次过收费站,剩余54036.008766264元
第 13 次过收费站,剩余51334.20832795元
第 14 次过收费站,剩余48767.497911553元
第 15 次过收费站,剩余43767.497911553元
第 16 次过收费站,剩余38767.497911553元
第 17 次过收费站,剩余33767.497911553元
第 18 次过收费站,剩余28767.497911553元
第 19 次过收费站,剩余23767.497911553元
第 20 次过收费站,剩余18767.497911553元
第 21 次过收费站,剩余13767.497911553元
第 22 次过收费站,剩余8767.497911553元
第 23 次过收费站,剩余3767.497911553元
******/for($money = 100000,$num=0; $money >= 5000; 这里是空的 )
第二个分号后";",竟然是空的,这样也可以的。
for循环括号里的三个语句,甚至可以一个都不用写
写一个最简单的for循环
/**
* 就两个分号
* 这个最简单的for循环会发生什么?
* 别运行死循环。
*
* 四个语句:
* 第一个语句,初始化的,初始化是空的就不执行
* 第二个语句,判断,没有就相当于没有门禁卡,直接就通过了
* 通过了,就运行echo 'haha'
* 执行完echo 'haha',第2个分号后的语句也是空的,空就空,不执行呗
* 于是有来到了第二条语句这,还是没有判断条件
* 因此,再执行echo 'haha'
* 就死循环了
*
*/
for(;;){
echo 'haha';
}VV:原来每个语句里可以定义多个参数
看上节课的,一次打印两个变量的for循环
定义两个变化$i、$j
让$i --
让$j ++
for循环比我们想象的要强大
for($i=5,$j=1; $i >= 1; $i--,$j++){
echo $i, '~~~~' ,$j , '<br>';
}
/***
打印结果:
5~~~~1
4~~~~2
3~~~~3
2~~~~4
1~~~~5
***/之前碰到一些怪事
1、023显示问题
2、二进制的问题
3、16进制的问题
4、16进制面试的问题
5、药死小白鼠的问题
以上,给我们带来的疑惑,都是因为进制的问题,接下来彻底学习进制的问题。
