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的值是6
2、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、药死小白鼠的问题
以上,给我们带来的疑惑,都是因为进制的问题,接下来彻底学习进制的问题。