PHP递归详解

article/2025/9/22 4:01:22

递归

  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);}}

http://chatgpt.dhexx.cn/article/fX8Y6EXd.shtml

相关文章

PHP 递归函数

递归函数即自调用函数&#xff0c;在函数体内部直接或间接的自己调用自己&#xff0c;即函数的嵌套调用就是函数本身。通常 在此类型的函数体中会附加一个条件判断&#xff0c;以判断是否需要执行递归调用&#xff0c;并且在特定的条件下终止函数的递归 调用动作&#xff0c;…

软件设计师考试感想随笔

带着紧张期待的心情查询了2021年下半年的软件设计师考试成绩&#xff0c;上午55分&#xff0c;下午66分&#xff0c;对这个成绩也算预料之中&#xff0c;因为我刚考完不到一个星期就在网上搜了答案对了成绩。 刚开始的时候买的纸质教程&#xff0c;厚厚的一本&#xff0c;还没看…

软考中级,软件设计师考试那些内容,考试大纲什么的?

一、中级软件设计师科目包括&#xff1a; &#xff08;1&#xff09;计算机与软件工程知识&#xff0c;考试时间为150分钟&#xff0c;笔试&#xff0c;选择题&#xff1b; &#xff08;2&#xff09;软件设计&#xff0c;考试时间为150分钟&#xff0c;笔试&#xff0c;问答…

软考软件设计师中级考试大纲(附题型举例)

软件设计师考试大纲 一、考 试 说 明 1&#xff0e;考试目标 通过本考试的合格人员能根据软件开发项目管理和软件工程的要求&#xff0c;按照系统总体设计规格说明书进行软件设计&#xff0c;编写程序设计规格说明书等相应的文档&#xff0c;组织和指导程序员编写、调试程序…

软考中级–软件设计师考试大纲

软考中级–软件设计师考试大纲 考试场数&#xff1a;上午&#xff08;基础理论&#xff0c;75个选择题&#xff0c;1空1分&#xff09;、下午&#xff08;案例分析&#xff0c;五个解答题&#xff0c;每道题15分&#xff09; 分数线&#xff1a; 上下午满分都是75分&#xff…

软件设计师提纲+复习资料整理(上午题)

文章目录 软件设计师考试大纲上午题&#xff08;选择题&#xff09;一、计算机组成原理考点&#xff1a;CPU结构组成考点&#xff1a;原码、反码、补码定点整数范围考点&#xff1a;浮点数表示考点&#xff1a;RISC和CISC计算机的区别考点&#xff1a;奇校验与偶校验考点&#…

【软考-软件设计师精华知识点笔记】考试大纲及题型介绍

前言 今年上半年参加了软件设计师考试&#xff0c;考完感觉稳了&#xff08;成绩下来已经通过了&#xff09;&#xff0c;考试内容与我学习的内容基本一致&#xff0c;因此感觉自己的笔记可以帮助其他准备考试的童鞋。总共十一章的笔记&#xff0c;已完成。如果未来有机会&…

struts2拦截器定义

为什么需要拦截器&#xff1a; 早起MVC框架将一些通用操作写死在核心控制器中&#xff0c;致使框架灵活性不足&#xff0c;可扩展性降低。Struts2将核心功能放在多个拦截器中实现&#xff0c;拦截器可自由选择和组合&#xff0c;增强了灵活性&#xff0c;有利于系统的解耦。 什…

Struts2拦截器-abstractInterceptor

通过继承AbstractInterceptor类&#xff0c;重写intercept方法&#xff0c;实现拦截器&#xff1b; 需要在Struts2中初始化需要放行的action名称 具体流程&#xff1a; 1.新建Struts2项目&#xff08;MyEclipse自动配置Struts2环境&#xff09; 2.新建页面&#xff08;index…

Struts2拦截器-MethodFilterInterceptor

Struts2拦截器-abstractInterceptor--在这篇博文的基础上进行修改&#xff1b; 1.页面1 2.页面2 3.新建实体 4.新建action 5.新建MethodFilterInterceptor拦截器继承MethodFilterInterceptor 6.配置拦截器

Struts2拦截器入门

Struts2的流程图 Struts2的处理流程 Struts2的拦截器中的分离关注 把过滤器要完成的事情委托给多个类完成&#xff0c;这种观点就是分离关注&#xff0c;过滤器负责调用这些类。 处理Cookies的拦截器&#xff08;处理web中的cookies&#xff09;令牌拦截器&#xff08;处理表…

struts2拦截器使用(部分拦截和全局拦截器)

应用场景:在请求处理之前拦截请求&#xff0c;做出相关处理。比如在一个网站中&#xff0c;用户尚未登录那么他是无法查看个人信息界面的。这时候我们就可以使用拦截器来拦截他访问个人信息的界面的请求。具体如下&#xff08;这里主要是struts2自定义拦截器的方法&#xff09;…

Struts 2拦截器

学习内容 拦截器工作原理 Struts 2自带拦截器 自定义拦截器 能力目标 熟悉Struts 2拦截器工作原理 熟练使用和配置拦截器 本章简介 上一章我们深入学习了Struts 2框架的配置&#xff0c;包括Action的配置、Result的配置等等&#xff0c;使我们对Struts 2框架有了更深的了解。…

Struts2拦截器的学习

一.首先我应该先要了解Struts2拦截器的执行原理 Struts 2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时&#xff0c;Struts 2会查找配置文件&#xff0c;并根据其配 置实例化相对的拦截器对象&#xff0c;然后串成一个列表&#xff08;list&#xff09;&#…

Struts2拦截器Filter

拦截器 拦截器Filter是Struts2的核心。 Struts2的拦截器与Servlet中的过滤器相似。 在执行Action的execute()方法之前&#xff0c;Struts2先执行struts.xml中引用的拦截器&#xff0c;在执行完所有引用的拦载器的doIntercept()方法后&#xff0c;会执行Action的execute()方法…

struts2拦截器

1. 拦截器 1.1 概述 基本概念 Intercetor, 即为拦截器。 1&#xff09; 在Struts2中&#xff0c;把每一个功能都用一个个的拦截器实现&#xff1b;用户想用struts的哪个功能的时候&#xff0c;可以自由组装使用。 2&#xff09;Struts2中&#xff0c;为了方法用户对拦截器的引…

struts2之拦截器详解

文章目录 1 拦截器1.1 拦截器是什么1.1.1 Struts2的拦截器的实现原理 1.2 拦截器的优点是什么1.3 预定义拦截器1.3.1 预定义拦截器1.3.1.1 params拦截器1.3.1.2 timer拦截器1.3.1.3 logger拦截器1.3.1.4 其他默认拦截器 1.3.2 拦截器配置说明1.3.3 拦截器的调用顺序1.3.4 全局拦…

Struts2之拦截器

目录 拦截器简介拦截器配置内建拦截器自定义拦截器使用拦截器实现权限控制拦截器工作原理 拦截器简介 拦截器&#xff08;Interceptor&#xff09;是Struts2的核心组成部分&#xff0c;它可以动态拦截Action调用的对象&#xff0c;类似于Servlet中的过滤器。 Struts2的拦截器是…