Ruanyifeng.com/blog/2008/12/the_perils_of_javaschools.html
指针和递归式计算机语言难以理解的地方。
PHP中没有指针的概念,但递归仍是重要内容
题目:求1到N的和?
方法一:
function sum($n){ for ($i=1,$sum=0; $i <=$n; $i++) { $sum=$sum+$i; } return $sum; } echo sum(100); |
方法二:
array_sum()计算数组中所有值的和 */ function sum1($n){ return array_sum(range(1,$n)); } echo sum1(100); |
方法三:
function sub($n){ if ($n>1) { return sub($n-1)+$n; } else { return 1; } } echo sub(100); |
递归打印级联目录
<?php /**** 递归打印级联目录 ****/ ─ //打印一层目录----如果还是目录,继续调用自身,直到不是目录 function recdir($path){ $handle = opendir($path); //打开目录,获取文件句柄 while (($res = readdir($handle)) !== false) { 读到的文件不等于false,则输出目录名 //首先读到的是当前目录和上级目录 ,要过滤掉 if ($res =="." || $res =="..") { continue; } echo $res."<br/>"; //如果$res还是目录,继续调用 if (is_dir($path."/".$res)) { recdir($path."/".$res); } } closedir($handle); } recdir("./"); ?> |
函数调用
开始执行 碰到return 或者执行到最后结束
递归调用函数,耗费资源,如果层数太深,不宜用递归
递归必须有一个终止条件
仿tree
<?php function recdir($path,$lev){ //增加一个层次计数器,每进入一层加一 $handle = opendir($path); while (($res = readdir($handle)) !== false) { if ($res =="." || $res =="..") { continue; } echo '--'.str_repeat('----', $lev).$res."<br/>"; if (is_dir($path."/".$res)) { recdir($path."/".$res,$lev+1); } } closedir($handle); } recdir(".",1); ?> |
递归创建普通目录
创建目录 echo mkdir("./".date("ymd")); echo mkdir("./b/c")?"ok":"fail"; |
失败,如果父目录不存在,子目录不能创建
Warning: mkdir() [function.mkdir]:
No such file or directory in C:\wamp\www\eshop\20140318\01_.php on line 6
Fail
第一种方法:
自定义函数,完成一次创建.a/b/c/d/e 级联目录 function createDir($path){ //判断是否是目录is_dir() if (is_dir($path)) {//如果目录已经存在,直接返回true return true; } //截取父目录dirname(),如果父目录存在,直接创建子目录 //目录已经存在,创建子目录 if (is_dir(dirname($path))) { return mkdir($path); } //父目录不存在,创建父目录 else{ createDir(dirname($path)); return mkdir($path); } } createDir("./z/x/c/v/b/n/m"); |
第二种:
1>如果目录存在,直接返回 2>如果目录不存在,创建: 只需要父目录存在,或者创建了父目录,才创建子目录 */ /*function mk_dir($path){ if (is_dir($path)) { return true; } //目录不存在,判断父目录是否存在、 //父目录存在则创建子目录,不存在,则创建目录 if(is_dir(dirname($path)) || mk_dir(dirname($path))){ mkdir($path); return true; } else return false; } mk_dir("q/w/e/r"); |
第三种:
mkdir(pathname)在PHP5.0,增加了第三个参数可以级联创建目录 第二个参数,是权限*/ mkdir("./new/new1/a/c/v",0777,true); |
递归删除目录:
<?php /**** 递归删除目录 ****/ function del_dir($path){ //不是目录,直接返回 if (!is_dir($path)) { return false; } //是目录,打开目录 $handle = opendir($path); //读取目录 while (($row = readdir($handle)) !==false) { //过滤当前目录和上级目录 if ($row == "." || $row=="..") { continue; } // 读到的不是目录,则是普通文件,直接删除 if (!is_dir($path."/".$row)) { unlink($path."/".$row); } //如果还是目录,再调用函数删除 else { del_dir($path."/".$row); } } //关闭文件资源 closedir($handle); //删除目录 rmdir($path); return true; } del_dir("./z"); ?> |
递归和迭代的区别:
<?php function rec_sum($n){ if ($n>1) { return $n+rec_sum($n-1); } else return 1; } //在递归调用计算出结果前,共有十个函数同时执行 echo rec_sum(10); //迭代实现 //迭代就是在某个范围内,反复执行完成相同工作 //递归 耗费资源 function it_sum($n){ for ($i=1; $i < $n; $i++) { $sum+=$i; } return $sum; } ?> |
迭代创建目录
<?php /**** 迭代创建级联目录 借助栈,递归都可以转化为迭代 ****/ function mk_dir($path){ $arr = array(); while (!is_dir($path)) { //传入的不是目录,放入数组 array_push($arr, $path); $path = dirname($path); } if (empty($arr)) { return true; } else { while (count($arr)) { mkdir(array_pop($arr)); } return true; } } mk_dir("./cc/dd/ee/ff"); ?> |
框架改进------递归转义:
利用系统函数转义:
<?php if (!get_magic_quotes_gpc()) { function _addslashes(&$v,$k){ $v = addslashes($v); } array_walk_recursive(&$_GET, '_addslashes'); array_walk_recursive(&$_POST, '_addslashes'); array_walk_recursive(&$_COOKIE, '_addslashes'); } ?> |
引用传参:
$age = 10; function grow($age){ $age+=1; return $age; } echo grow($age);//11 echo $age;//10 |
$age = 10; function grow($age){ $age+=1; return $age; } echo grow(&$age);//11 echo $age;//11 |
引用传值
内部函数的$age 和全局的$age 指向同一个变量地址
内部变化,影响外部变化
违反了封装性,
函数运行讲究对外部环境没有副作用
& 传递的是地址*/
Warning: Call-time pass-by-reference has been deprecated;
If you would like to pass it by reference,
modify the declaration of grow().
If you would like to enable call-time pass-by-reference,
you can set allow_call_time_pass_reference to true
in your INI file in
PHP 5.0以上不推荐使用
在配置文件中
设置引用传参就警告
allow_call_time_pass_reference = on
error_reporting(E_ALL | E_STRICT)
PHP5.4 删除了这个引用传参功能
大于此版本,对此功能不支持了,
会出现fatal error
解决方法:
1. allow_call_time_pass_reference = on,并重启apache
2.不引用传参,自己写方法递归转义数组
利用递归实现转义
<?php /**** 递归转义数组 ****/ $arr = array('a"b',array("'c'd",array('e"f'))); //先转义一维数组,再判断还是数组,在调用自身转义 function _addslashes($arr){ foreach($arr as $k=>$v){ if (is_string($v)) { $arr[$k] = addslashes($v); } else if (is_array($v)) { $arr[$k] = _addslashes($v); } } return $arr; } print_r(_addslashes($arr)); //如果要改变全局$arr的值,需要重新赋值 ?> Array ( [0] => a\"b [1] => Array ( [0] => \'c\'d [1] => Array ( [0] => e\"f ) ) ) |
商城项目改进:
创建lib_base.php
// 递归转义数组 function _addslashes($arr) { foreach($arr as $k=>$v) { if(is_string($v)) { $arr[$k] = addslashes($v); } else if(is_array($v)) { // 再加判断,如果是数组,调用自身,再转 $arr[$k] = _addslashes($v); } } return $arr; } |
在init.php中修改:
// 过滤参数,用递归的方式过滤$_GET,$_POST,$_COOKIE,暂时不会 $_GET = _addslashes($_GET); $_POST = _addslashes($_POST); $_COOKIE = _addslashes($_COOKIE); |
测试递归转义
$t1 = $_GET["t1"]; $t2 = $_GET["t2"]; $sql = "insert into test(t1,t2) values('$t1','$t2')"; var_dump($mysql->query($sql));*/ var_dump($mysql->autoExcute('test',$_GET,'insert')); |