Go to comments

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 '没有传值';

}

上面的代码,已经用上了流程控制,即我们学的控制结构

有几种控制结构

这三种控制结构,所有语言都一样。

几十年来,为什么没有发展出第四种类控制结构?

有一位计算机科学家写过一篇论文,这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

三、循环结构

编程语言中,一般都有这几种循环:

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、药死小白鼠的问题

以上,给我们带来的疑惑,都是因为进制的问题,接下来彻底学习进制的问题。



Leave a comment 0 Comments.

Leave a Reply

换一张