php函数引用返回的详解

 更新时间:2016年11月25日 15:33  点击:1882
函数引用与php中变量引用一样使用的是&符号了,今天我们就一起来看看函数的引用返回的一些例子,希望这些例子能够对各位有帮助.

引用返回

手册里是这么写的:引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。不要用返回引用来增加性能,引擎足够聪明来自己进行优化。仅在有合理的技术原因时才返回引用!要返回引用

当你想将函数的返回引用绑定到某个变量时,PHP允许你这么做:

function &returns_reference()
{
    static $someref = 0;
    $someref++;
    return $someref;
}
 
$newref = &returns_reference();//引用返回,相当于 $newref = &$someref;
echo $newref; //1
 
$notref = returns_reference(); //值传递的是副本
$newref = 100;
echo $notref; //2
 
$newref = 100;
echo returns_reference(); //101

可见,想让函数返回引用,必须在函数申明和赋值时都带上&操作符。
对于类中方法也是如此:

class foo {
    public $value = 0;
 
    public function &getValue() {
        return $this->value;
    }
}
 
$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue;


一些简单的例子

看下面的简单例子,尝试去理解引用返回。

<?php

function &test()
{
 // 声明一个静态变量
    static $b = 0;

    $b = $b+1;
    echo $b;
    return $b;
}

$a = test(); //这条语句会输出 $b 的值为 1

$a = 5;
$a = test(); //这条语句会输出 $b 的值为2

$a = &test(); //这条语句会输出 $b 的值为3

$a = 5;
$a = test(); //这条语句会输出 $b的值 为6

?>
程序运行结果:

1
2
3
6

尽管函数声明方式是 function &test() 这样,但我们通过这种方式 $a = test() 的函数调用得到的其实不是函数的引用返回,这跟普通的函数调用没有区别。PHP 规定通过 $a = &test() 这种方式得到的才是函数的引用返回。
用上面的例子来解释就是,$a = test() 这种方式调用函数,只是将函数的值赋给 $a 而已,而$a做任何改变都不会影响到函数中的$b。

而通过 $a = &test() 方式调用函数呢,它的作用是将 return $b 中的 $b 变量的内存地址与 $a 变量的内存地址指向了同一个地方。即产生了相当于这样的效果 ($a=&$b), 所以改变 $a 的值也同时改变了 $b 的值。所以在执行了

$a = &test();
$a = 5;
以后,$b的值变为了5。

再来个程序例子加深理解:

<?php
/*
** 值传递和引用传递,值传递传递的是值的一个复本,引用传递传递的是值指向的内存地址
*/

// 函数的引用,定义时也要加上 &
function &func($a,$b){  
 // 这里为了更直观看到效果,定义一个静态变量
 static $result = 0;   
 $result+=$a+$b;
 echo $result.'<br />';
 return $result;
}
 
$a = $b = 10;

// PHP里这样写函数的引用调用,和调用普通函数没有区别(只是将函数的返回值复制给$c这个变量,$c做任何改变不会影响上面函数中的$result)
// 要记住:PHP里的函数引用定义及调用都要在函数名前加上 &
$c = func($a,$b);
// 第一次执行func(),其静态变量$result的值变为 20(10+10)

// 改变$c的值,不会对下面一行语句产生影响
$c = 666; 
// 第二次执行func(),其静态变量$result的值变为 40(20+10+10)
$c = func($a,$b);

echo '<hr />';

// 这样才是PHP中引用函数的调用方式
$d = &func($a,$b); 
// 第三次执行func(),其静态变量$result的值变为 40(40+10+10)
$d = 888;
// 第四次执行func(),其静态变量$result的值变为 908(888+10+10)
$d = func($a,$b);

?>

 

CWidget是所有Widget的基类。CWidget是自包含组件,可以看出是MVC的简略版,CWidget相比Controller,既没有actions,也没有filters

widget,英文意思为小工具,小挂件,在程序里大概也是这个意思,Yii2中叫做组件,这个示例仅仅是写一个基本的Yii2 widget,看看能不能运行。

关于widgets,他们在yii中的关系如下

system.web.widgets  系统自带最基本的widget
zii.widgets  是基本扩展
zii.widgets.grid  是基本扩展的重要分支
zii.widgets.jui  是插件扩展

一,system.web.widgets

包括:
    CActiveForm
    CAutoComplete
    CClipWidget
    CContentDecorator
    CFilterWidget
    CFlexWidget
    CHtmlPurifier
    CInputWidget
    CMarkdown
    CMaskedTextField
    CMultiFileUpload
    COutputCache
    COutputProcessor
    CStarRating
    CTabView
    CTextHighlighter
    CTreeView
    CWidget


看vendor/yiisoft/yii2/base/Widget.php的定义,widget需要继承这个类,begin,end,widget,run这些方法都可以在子类进行重写定义,这里我们重写run试试。


新建一个类Testwidgets.php:

namespace common\widgets;
 
use yii\base\Widget;
 
 
class Testwidgets extends Widget
{
    public function __Construct()
    {
        echo 'test test ...';
    }
 
    public function run()
    {
        echo 'run run run ...';
    }
}
在一个模板文件中这样使用:


<?php
/* @var $this yii\web\View */
 
use common\widgets\Testwidgets;
 
?>
 
<p>
    <?php echo Testwidgets::widget();?>
</p>
页面输出:

test test …run run run …

是不是很简单,当然这只是一个最简单的Yii2 widget,只是搞清楚写widget的基本方式。

比如Yii2的表单widget,涉及到很多用法,就要定义额外的类和方法来实现需求。


    <?php $model = new User();?>
    <?php $form = ActiveForm::begin(['id'=>'login-form']);?>
    <?= $form->field($model,'username')->label('用户名') ?>
    <?= $form->field($model,'password_hash')->passwordInput()->label('密码') ?>
    <?php ActiveForm::end() ;?>

这样就很方便生成一个表单,而且可以灵活设置各种属性,其实原理都是一样的。

关于Yii2的表单widget,可以好好研究一下,写的很妙。两个文件:

vendor/yiisoft/yii2/widgets/ActiveForm.php和vendor/yiisoft/yii2/widgets/ActiveField.php


使用示例

Yii2封装了一个表单widget,很方便生成各类各式的表单,试了几种表单,可以自由设置样式、类型、属性,如下代码:


    <?php $model = new User();?>
    <?php $form = ActiveForm::begin(['id'=>'login-form']);?>
    <?= $form->field($model,'username')->label('用户名') ?>
    <?= $form->field($model,'password_hash')->passwordInput()->label('密码') ?>
    <?= $form->field($model,'email')->textarea(['rows'=>5]) ?>
    <?= $form->field($model,'status')->checkboxList([1=>'hehe',2=>'haha',3=>'xixi',4=>'heihei'],['id'=>'dddd'])->label('多选') ?>
    <?php ActiveForm::end() ;?>


如果想更全面了解如何使用,还是需要看一看源码,才能更好的灵活使用yii2的生成表单widget.

源码文件位置:vendor/yiisoft/yii2-gii/components/ActiveField.php

防止重复提交表单的方法小编介绍过的不知道有多案了,如数据库判断,js验证,cookies验证及session验证,下面一起来看一个例子。

我们提交表单的时候,不能忽视的一个限制是防止用户重复提交表单,因为有可能用户连续点击了提交按钮或者是攻击者恶意提交数据,那么我们在提交数据后的处理如修改或添加数据到数据库时就会惹上麻烦。


那么如何规避这中重复提交表单的现象出现呢?我们可以从很多方面入手,首先从前端做限制。前端JavaScript在按钮被点击一次后禁用,即disabled,这个方法简单的防止了多次点击提交按钮,但是缺点是如果用户禁用了javascript脚本则失效。第二,我们可以在提交后做redirect页面重定向,即提交后跳转到新的页面,主要避免F5重复提交,但是也有不足之处。第三,就是数据库做唯一索引约束。第四,就是做session令牌验证。

我们现在来了解下简单的利用session token来防止表单重复提交的方法。
我们在表单中加一个input隐藏域,即type="hidden",其value值用来保存token值,当页面刷新的时候这个token值会变化,提交后判断token值是否正确,如果前台提交的token与后台不匹配,则认为是重复提交。

 代码如下 复制代码
<?php
/*
* PHP简单利用token防止表单重复提交
*/
session_start();
header("Content-Type: text/html;charset=utf-8");
function set_token() {
    $_SESSION['token'] = md5(microtime(true));
}
 
function valid_token() {
    $return = $_REQUEST['token'] === $_SESSION['token'] ? true : false;
    set_token();
    return $return;
}
 
//如果token为空则生成一个token
if(!isset($_SESSION['token']) || $_SESSION['token']=='') {
    set_token();
}
 
if(isset($_POST['web'])){
    if(!valid_token()){
        echo "token error,请不要重复提交!";
    }else{
        echo '成功提交,Value:'.$_POST['web'];
    }
}else{
?>
    <form method="post" action="">  
        <input type="hidden" name="token" value="<?php echo $_SESSION['token']?>">  
        <input type="text" class="input" name="web" value="www,111cn.net">  
        <input type="submit" class="btn" value="提交" />  
    </form>
<?php    
}
?>

以上是一个简单的防止重复提交表单的例子,仅供参考。那么实际项目开发中,会对表单token做更复杂的处理,即我们说的令牌验证。可能要做的处理有:验证来源域,即来路,是否为外部提交;匹配要执行的动作,是添加、修改or删除;其次最重要的是构建token,token可以采用可逆的加密算法,尽可能复杂,因为明文还是不安全的。令牌验证的具体算法可以参考各大PHP框架,如ThinkPHP提供了很好的令牌验证功能。

生成IP我们只要生成一个字符串就可以了,在指定范围的int可存储的空间中就可以生成ipv4的ip数据了,下面我们一起来来看看.

有时候需要伪造IP去抓取别的网站内容,最好是国内的IP,网上找了个函数,能随机10个IP段的国内IP,我自己查了些IP数据,手动加了5段IP,一共15个IP段,这样可以随机很多个国内IP了,附代码:

function rand_ip(){
 $ip_long = array(
  array('607649792', '608174079'), //36.56.0.0-36.63.255.255
  array('975044608', '977272831'), //58.30.0.0-58.63.255.255
  array('999751680', '999784447'), //59.151.0.0-59.151.127.255
  array('1019346944', '1019478015'), //60.194.0.0-60.195.255.255
  array('1038614528', '1039007743'), //61.232.0.0-61.237.255.255
  array('1783627776', '1784676351'), //106.80.0.0-106.95.255.255
  array('1947009024', '1947074559'), //116.13.0.0-116.13.255.255
  array('1987051520', '1988034559'), //118.112.0.0-118.126.255.255
  array('2035023872', '2035154943'), //121.76.0.0-121.77.255.255
  array('2078801920', '2079064063'), //123.232.0.0-123.235.255.255
  array('-1950089216', '-1948778497'), //139.196.0.0-139.215.255.255
  array('-1425539072', '-1425014785'), //171.8.0.0-171.15.255.255
  array('-1236271104', '-1235419137'), //182.80.0.0-182.92.255.255
  array('-770113536', '-768606209'), //210.25.0.0-210.47.255.255
  array('-569376768', '-564133889'), //222.16.0.0-222.95.255.255
 );
 $rand_key = mt_rand(0, 14);
 $huoduan_ip= long2ip(mt_rand($ip_long[$rand_key][0], $ip_long[$rand_key][1]));
 return $huoduan_ip;
}

补充:long2ip函数

把存储空间降到了接近四分之一(char(15)的15个字节对整形的4个字节),计算一个特定的地址是不是在一个区段内页更简单了,而且加快了搜索和排序的速度(虽然有时仅仅是快了一点)。

例子

$ip = long2ip(3232235881);  
echo $ip;//127.255.255.255

下面我们一起来看一篇关于SAE 上安装 Wecenter 错误问题处理例子,希望这篇文章能够帮助到各位朋友。

今天其实想搭建个社区,专门为 Zephir/Phalcon/Yaf/Docker/Swoole 建设一个社区, 专门为 C 语言的PHP框架和 C 语言扩展做一个,刚开始挺高兴的,直接用 wecenter 搭建多好,而且官网说支持 SAE,我就信心满满的去了,结果不行,坑爹呀,新浪那么大字,mysql 不支持 host:port 没看吗? 稍微修改一下就可以了。
0x01

修改 system\Zend\Db\Adapter\Mysqli.php ,搜索找到 // Suppress connection warnings here. ,然后在上边加入以下代码:

  

 代码如下 复制代码
  //修复SAE上连接错误 BUG add by widuu 2015/4/23
    if (defined('IN_SAE')){
        $host = $this->_config['host'];
        $this->_config['host'] = strstr($host,':',true);
        $port = trim(strstr($host,':'),':');
    }
    // end by widuu

修改 system\Zend\Db\Adapter\Pdo\Abstract.php,搜索一下代码:

 代码如下 复制代码
return $this->_pdoType . ':' . implode(';', $dsn);

然后替换成如下这样:

 代码如下 复制代码

//修复SAE上连接错误 BUG add by widuu 2015/4/23
if (defined('IN_SAE')){
     $host = $dsn['host'];
     $dsn['host'] = strstr($host,':',true);
     $dsn['port'] = 'port='.trim(strstr($host,':'),':');
}
// end by widuu
return $this->_pdoType . ':' . implode(';', $dsn);
0x02

伪静态不管用,大哥你知道吗,最好看看官方的 API,然后伪静态变成如下就可以了:

name: 你的应用名称
version: 你的版本
handle:

 代码如下 复制代码
- rewrite: if (!-d && !-f) goto "/index.php?%{QUERY_STRING}"

好就到这里,明天预告,更新 Phalcon 的东西,我也想更新 YAF 的知识,当然一个一个慢慢来。然后是 Zephir。

[!--infotagslink--]

相关文章

  • php正确禁用eval函数与误区介绍

    eval函数在php中是一个函数并不是系统组件函数,我们在php.ini中的disable_functions是无法禁止它的,因这他不是一个php_function哦。 eval()针对php安全来说具有很...2016-11-25
  • php中eval()函数操作数组的方法

    在php中eval是一个函数并且不能直接禁用了,但eval函数又相当的危险了经常会出现一些问题了,今天我们就一起来看看eval函数对数组的操作 例子, <?php $data="array...2016-11-25
  • Python astype(np.float)函数使用方法解析

    这篇文章主要介绍了Python astype(np.float)函数使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-08
  • Python中的imread()函数用法说明

    这篇文章主要介绍了Python中的imread()函数用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-16
  • C# 中如何取绝对值函数

    本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
  • C#学习笔记- 随机函数Random()的用法详解

    下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • mybatis-plus 返回部分字段的解决方式

    这篇文章主要介绍了mybatis-plus 返回部分字段的解决方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-02
  • 金额阿拉伯数字转换为中文的自定义函数

    CREATE FUNCTION ChangeBigSmall (@ChangeMoney money) RETURNS VarChar(100) AS BEGIN Declare @String1 char(20) Declare @String2 char...2016-11-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • PHP用strstr()函数阻止垃圾评论(通过判断a标记)

    strstr() 函数搜索一个字符串在另一个字符串中的第一次出现。该函数返回字符串的其余部分(从匹配点)。如果未找到所搜索的字符串,则返回 false。语法:strstr(string,search)参数string,必需。规定被搜索的字符串。 参数sea...2013-10-04
  • PHP函数分享之curl方式取得数据、模拟登陆、POST数据

    废话不多说直接上代码复制代码 代码如下:/********************** curl 系列 ***********************///直接通过curl方式取得数据(包含POST、HEADER等)/* * $url: 如果非数组,则为http;如是数组,则为https * $header:...2014-06-07
  • php中的foreach函数的2种用法

    Foreach 函数(PHP4/PHP5)foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。...2013-09-28
  • C语言中free函数的使用详解

    free函数是释放之前某一次malloc函数申请的空间,而且只是释放空间,并不改变指针的值。下面我们就来详细探讨下...2020-04-25
  • SQLMAP结合Meterpreter实现注入渗透返回shell

    sqlmap 是一个自动SQL 射入工具。它是可胜任执行一个广泛的数据库管理系统后端指印, 检索遥远的DBMS 数据库等,下面我们来看一个学习例子。 自己搭建一个PHP+MYSQ...2016-11-25
  • PHP函数strip_tags的一个bug浅析

    PHP 函数 strip_tags 提供了从字符串中去除 HTML 和 PHP 标记的功能,该函数尝试返回给定的字符串 str 去除空字符、HTML 和 PHP 标记后的结果。由于 strip_tags() 无法实际验证 HTML,不完整或者破损标签将导致更多的数...2014-05-31
  • PHP加密解密函数详解

    分享一个PHP加密解密的函数,此函数实现了对部分变量值的加密的功能。 加密代码如下: /* *功能:对字符串进行加密处理 *参数一:需要加密的内容 *参数二:密钥 */ function passport_encrypt($str,$key){ //加密函数 srand(...2015-10-30
  • SQL Server中row_number函数的常见用法示例详解

    这篇文章主要给大家介绍了关于SQL Server中row_number函数的常见用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-08
  • php的mail函数发送UTF-8编码中文邮件时标题乱码的解决办法

    最近遇到一个问题,就是在使用php的mail函数发送utf-8编码的中文邮件时标题出现乱码现象,而邮件正文却是正确的。最初以为是页面编码的问题,发现页面编码utf-8没有问题啊,找了半天原因,最后找到了问题所在。 1.使用 PEAR 的...2015-10-21
  • C#中加载dll并调用其函数的实现方法

    下面小编就为大家带来一篇C#中加载dll并调用其函数的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25