PHP递归详解

递归
  1. 递归是一种函数调用自身的机制
  2. 递归必须要有边界条件,也就是递归出口(退出递归)
  3. 递归前进段和递归返回段,也就是最后得到的值
  4. 当边界条件不满足时,递归前进;当边界条件(递归出口)满足时,递归返回

递归就是函数自己调用自身

递归计算阶乘
在这里插入图片描述

输出结果
在这里插入图片描述
很明显的可以看到计算6!时,是6*5*4*3*2*1,这就实现了递归。
例子: 目录的递归遍历

function loop_dir($path)
{      
    $dh = opendir($path);      
    while($file=readdir($dh) !== false) {            
        $current_file = $path.DIRECTORY_SEPARATOR.$file;           
        if($file == '.' || $file == '..') {                 
            continue;            
        } elseif (is_dir($current_file)) {                  
            echo 'Directory '.$current_file.':<br>';                  
            loop_dir($current_file);            
        } else {                  
            echo 'File in Directory '.$path.': '.$file.'<br>';            
        }      
    }      
    closedir();              //不加参数,关闭的是打开的最近打开的句柄,这样就保证函数结束时,关闭所有的句柄
}
利用递归函数处理多维数组

将多维数组中空的子数组删除

/**去除多维数组中空子数组
     * @param $arrayInput
     * @return mixed
     */
    static function removeEmptyArray(&$arrayInput)
    {
        foreach ($arrayInput as $sInputKey => $arrInputValue) {

            if (empty($arrInputValue)) {
                unset($arrayInput[$sInputKey]);
            } elseif (is_array($arrInputValue)) {
                self::removeEmptyArray($arrInputValue);
            } else {
                break;
            }
        }

        return $arrayInput;
    }

通过筛选串数组([’*.A.B’, ‘C’])去除多维数组中多余的字段

   /**
     * 取得当前深度的筛选串
     * @param string $sField
     * @param int $nDepth 当前遍历数组深度
     * @return string
     */
    static function getFields($sField, $nDepth = 1)
    {
        $arrParts = explode('.', $sField, $nDepth + 1);
        if (count($arrParts) > 1 && count($arrParts) > $nDepth) {
            array_pop($arrParts);
        }
        $sFieldsOfTheDepth = implode('.', $arrParts);

        return $sFieldsOfTheDepth;
    }


    /**
     * 取得字符串的总深度
     * @param string $sPath
     * @return int
     */
    static function getTotalDepth($sPath)
    {
        $nFieldTotalDepth = substr_count($sPath, '.') + 1;
        return $nFieldTotalDepth;
    }


    /**去除多维数组中空子数组
     * @param $arrayInput
     * @return mixed
     */
    static function removeEmptyArray(&$arrayInput)
    {
        foreach ($arrayInput as $sInputKey => $arrInputValue) {

            if (empty($arrInputValue)) {
                unset($arrayInput[$sInputKey]);
            } elseif (is_array($arrInputValue)) {
                self::removeEmptyArray($arrInputValue);
            } else {
                break;
            }
        }

        return $arrayInput;
    }


    /**返回字符串的第一个单词 如: A.B.C 中的A
     * @param string $sPath
     * @return string
     */
    static function handlePath($sPath)
    {
        $nFirstPath = strpos($sPath, '.');
        if ($nFirstPath) {
            $sFirstPath = substr($sPath,0, $nFirstPath);
        } else {
            return $sPath;
        }

        return $sFirstPath;
    }


    /**
     * 递归比较子数组和筛选数组的路径串, 并筛选
     * @param array $arrSubArray 子数组
     * @param int $nDepth 实际数组下标深度
     * @param array $arrFields 筛选数组
     * @param string $sPartPath 源数组到子数组的实际路径串
     * @param string $sMethodSource 方法名 'exceptFields', 'onlyFields'
     * @return array 返回经过字段筛选后的数组
     */
    static function pathFilter(&$arrSubArray, $nDepth, $arrFields, $sPartPath, $sMethodSource)
    {
    //遍历筛选数组
        foreach ($arrFields as $sField) {
        //获取当前深度的筛选串路径
            $sTheDepthFields     = self::getFields($sField, $nDepth);
            //获取筛选串的总长度, 用于在删除数组键值对时作为标记
            $sTheTotalDepthField = self::getTotalDepth($sField);
             //获取当前筛选串的深度, 用于在删除时和$sTheDepthFields作比较
            $nNowDepthFields     = self::getTotalDepth($sTheDepthFields);
            //判断当前筛选串第一个字符是不是'*'
            $bIsWildCard         = strpos($sField, '*') == 0 ? true : false;
	    //遍历当前需要筛选的数组
            foreach ($arrSubArray as $sSubKey => $arrArray) {
                //拼接当前实际数组路径
                $sPartPath             .= '.' . $sSubKey;
                $sPartPath              = ltrim($sPartPath, ".");
                //获取当前实际数组路径的第一个单词
                $sFirstPartPath         = self::handlePath($sPartPath);
                //获取当前实际数组路径的总深度, 用于在删除数组键值对时作为标记判断
                $sTheTotalDepthPartPath = self::getTotalDepth($sPartPath);
		//把当前筛选串第一个字母是'*'和当前实际数组路径的第一个单词进行替换
                if ($bIsWildCard) {
                    $sTheDepthFields = str_replace('*', $sFirstPartPath, $sTheDepthFields);
                }
                //对当前的筛选串路径和实际数组路径进行比较
                $bJudge = $sTheDepthFields == $sPartPath ? true : false;

                switch ($sMethodSource) {
                    case 'exceptFields':

                        if ($bJudge && ($sTheTotalDepthPartPath == $sTheTotalDepthField)) {
                            unset($arrSubArray[$sSubKey]);
                            //将当前实际数组路径删除数组的键 例:A.B => A
                            $sPartPath = substr($sPartPath, 0, strlen($sPartPath) - strlen($sSubKey) - 1 );
                            continue 2;
                        } elseif (is_array($arrArray)) {
                            $nDepth++;
                            $arrSubArray[$sSubKey] = self::pathFilter($arrArray, $nDepth, $arrFields, $sPartPath, $sMethodSource);
                        }

                        break;
                    case 'onlyFields':

                        if (!$bJudge && ($nNowDepthFields == $sTheTotalDepthPartPath)) {
                            unset($arrSubArray[$sSubKey]);
                            $sPartPath = substr($sPartPath, 0, strlen($sPartPath) - strlen($sSubKey) - 1 );
                            continue 2;
                        } elseif (is_array($arrArray)) {
                            $nDepth++;
                            $arrSubArray[$sSubKey] = self::pathFilter($arrArray, $nDepth, $arrFields, $sPartPath, $sMethodSource);
                            //处理当前实际总的数组路径小于总的筛选串路径情况 例如: 筛选串 : *.META    当前总的数组路径 : ['K' => '1222']
                        } elseif ($sTheTotalDepthField > $sTheTotalDepthPartPath) {
                            unset($arrSubArray[$sSubKey]);
                        }
                        //这里对当前空数组进行删除操作
                        self::removeEmptyArray($arrSubArray);

                        break;
                }
                //针对于遍历完一个子数组, 将子数组第一个单词给还原为'*' | ' ' | '原单词'
                if (strlen($sPartPath) > strlen($sSubKey)){
                    $sPartPath = substr($sPartPath, 0, strlen($sPartPath) - strlen($sSubKey) - 1 );
                } else {
                    $sPartPath = '';
                }
//针对于遍历完一个子数组, 将筛选串第一个单词给还原为'*' | ' ' | '原单词'
                if ($bIsWildCard ) {
                    $sFirstFields = self::handlePath($sTheDepthFields);
                    $sTheDepthFields = str_replace($sFirstFields, '*', $sTheDepthFields);
                }
            }
        }

        return $arrSubArray;
    }


    /**
     * 筛选数组中的字段,仅保留指定的字段
     * @param array $arrArray 要筛选的源数组
     * @param string|array $arrFields 如:'*.meta.user_id'
     */
    public static function onlyFields(&$arrArray, $arrFields)
    {
        $arrFields = (array)$arrFields;
        self::pathFilter($arrArray, 1, $arrFields, '', 'onlyFields');
        self::removeEmptyArray($arrArray);
    }


    /**
     * 筛选数组中的字段,除了指定的字段,其它字段全部保留
     * @param array $arrArray 要筛选的源数组
     * @param string|array $arrFields 如:['*.meta.password', '*.deleted_at']
     */
    public static function exceptFields(&$arrArray, $arrFields)
    {
        $arrFields = (array)$arrFields;
        self::pathFilter($arrArray, 1, $arrFields, '', 'exceptFields');
        self::removeEmptyArray($arrArray);
    }


}
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值