V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
silenceeeee
V2EX  ›  PHP

php 返回引用的疑问

  •  
  •   silenceeeee · 2016-11-16 22:49:30 +08:00 · 3322 次点击
    这是一个创建于 2719 天前的主题,其中的信息可能已经有所发展或是发生改变。
    class a{
    
        public $a = 5;
    
    }
    
    function &load_class(){
    
        static $_classes = array();
        
        if (!isset($_classes['a'])){
        
            $_classes['a'] = new a();
            
        }
        return $_classes['a'];
        
    }
    
    $obj = &load_class();
    
    echo $obj->a;
    
    $obj->a = 1;
    
    $obj2 = &load_class();
    
    echo $obj2->a;
    
    echo PHP_EOL;
    
    exit;
    

    这段代码为什么会输出: 51 而不是: 55 ?

    32 条回复    2016-11-18 10:28:35 +08:00
    jarlyyn
        1
    jarlyyn  
       2016-11-16 23:10:10 +08:00
    因为$obj2==$obj
    AbrahamGreyson
        2
    AbrahamGreyson  
       2016-11-16 23:20:31 +08:00 via iPhone
    考察的就是那个 static 关键字,翻文档去吧
    eoo
        3
    eoo  
       2016-11-16 23:39:44 +08:00 via Android
    屎一样的代码。。。
    Sunyanzi
        4
    Sunyanzi  
       2016-11-16 23:54:51 +08:00   ❤️ 1
    这事情跟返回引用其实一点关系都没有 ... 你去掉这段程序里所有的 & 依然可以得到一样的结果 ...

    我试着改一下这个代码看看会不会看起来更清晰 ...

    ```php
    <?php
    class a { public $a = 5; }

    function load_class(){
    static $_c = [];

    if ( ! isset( $_c['a'] ) ) {
    echo 2;
    $_c['a'] = new a();
    }
    return $_c['a'];
    }

    $obj = load_class();
    echo $obj->a;
    $obj->a = 1;
    $obj2 = load_class();
    echo $obj2->a, load_class()->a, PHP_EOL;

    ```

    假装支持 markdown ... 能明白这段程序为什么输出 2511 么 ..?

    如果实在想不明白 ... 看这里 http://php.net/manual/en/language.oop5.static.php ...
    shell92
        5
    shell92  
       2016-11-17 00:35:09 +08:00
    看到 php 就头大
    shell92
        6
    shell92  
       2016-11-17 00:36:27 +08:00
    。。。。。
    shell92
        7
    shell92  
       2016-11-17 00:39:36 +08:00
    这个应该有!
    haiyang416
        8
    haiyang416  
       2016-11-17 00:41:15 +08:00 via Android
    有必要用这么脏的代码把自己绕进去么。。
    silenceeeee
        9
    silenceeeee  
    OP
       2016-11-17 06:54:20 +08:00 via iPhone
    @eoo 你这种回答跟屎有什么两样
    silenceeeee
        10
    silenceeeee  
    OP
       2016-11-17 07:46:04 +08:00
    各位 统一回复下 是我逗逼了
    我是理解 static 的 脑子短路了 一直把输出结果想成了 55 而在想为什么不输出 51 其实它本来就输出的 51
    silenceeeee
        11
    silenceeeee  
    OP
       2016-11-17 08:02:46 +08:00
    @haiyang416 说真的 我并不觉得这个代码混乱 这是 CI 框架中的一个方法 只是 我为了测试 把我不需要的代码去掉了 应该不难看出 这个方法(被我去掉一部分代码之前)本来是用注册表模式和单例结合起来返回一个类的实例 你觉得哪里不太好 可以讲出来探讨探讨啊 ~
    silenceeeee
        12
    silenceeeee  
    OP
       2016-11-17 08:05:15 +08:00
    @Sunyanzi 这个看下我 10 楼的回复
    silenceeeee
        13
    silenceeeee  
    OP
       2016-11-17 08:09:19 +08:00
    @Sunyanzi 另外 在顺带看你发的 PHP 手册链接时 又看到一个内容 不太理解 你看能否解释下
    http://php.net/manual/zh/language.variables.scope.php 这个页面的 "全局和静态变量的引用" 小节里面的代码:
    ```
    <?php
    function test_global_ref() {
    global $obj;
    $obj = &new stdclass;
    }

    function test_global_noref() {
    global $obj;
    $obj = new stdclass;
    }

    test_global_ref();
    var_dump($obj);
    test_global_noref();
    var_dump($obj);
    ```
    为啥会输出:
    NULL
    object(stdClass)(0) {
    }
    按我理解的话 应该都输出 object(stdClass)(0) {}才对啊
    silenceeeee
        14
    silenceeeee  
    OP
       2016-11-17 08:27:01 +08:00
    对 13 楼作如下补充:
    13 楼的问题或许可以直接描述为:
    $a = new stdclass;
    $b = &new stdclass;
    这两种生成对象的方式有什么本质上的区别
    感觉 php 的引用概念好模糊 C 的就相对清晰
    millson
        15
    millson  
       2016-11-17 09:41:32 +08:00
    static 在 php 中还是很常用的
    Sunyanzi
        16
    Sunyanzi  
       2016-11-17 10:09:32 +08:00
    @silenceeeee 你要知道 Assigning the return value of new by reference 已经不复存在了 ...

    也就是说这是段过时的代码 ... 为什么这么表现手册上已经说的很清楚了 ... 四个字历史遗留 ...

    这段代码在 php5 全系列都会有报错提醒 ... 所以其实了解这个对你学习 php 没什么用处 ...

    不过如果你要是想深入研究 php 的话我也可以解释给你 ... 不过不确定你是否能听懂就是了 ...
    silenceeeee
        17
    silenceeeee  
    OP
       2016-11-17 11:09:16 +08:00
    @Sunyanzi 以上你解释的这些其实我都知道的
    关于函数返回引用值在 PHP5 中的变更;
    关于这段代码是过时的代码;
    我觉得这个问题这样打字不太好描述 同样 你给我解释可能也不太好描述 另外 我有点 C 基础 有指针的概念 如果你方便的话 我还是很希望你能跟我解释下的
    haiyang416
        18
    haiyang416  
       2016-11-17 11:44:37 +08:00 via Android
    @silenceeeee PHP 的引用和指针式两码事,不要和指针联系起来。我觉得只要简单的记住不要使用 & 来 rebind 不在 scope 内的 reference 就行。 test_global_ref 中 global 申明的引用 $obj 不在 test_global_ref 的 scope 内。

    另外, 13 楼的代码在 Ubuntu14.04 PHP 5.5.9 上没有任何错误提示,运行结果和示例中的一致。
    silenceeeee
        19
    silenceeeee  
    OP
       2016-11-17 11:56:52 +08:00
    @haiyang416 这个问题打算到此为止 可能像你说的 只能先避免这样的问题吧
    我个人觉得 PHP 官方文档不足以解释这个问题了 要真的弄明白它 可能看 PHP 的源码比较靠谱

    总之 谢谢大家的回复!
    Sunyanzi
        20
    Sunyanzi  
       2016-11-17 12:10:07 +08:00
    @haiyang416 php 的引用确实和指针是两码事这点没错 ... 其他完全不是你说的这样 ...

    不过既然问题都结了我也就懒得再解释了 ... 另外你确定下开了 E_DEPRECATED 级别的报错 ...
    haiyang416
        21
    haiyang416  
       2016-11-17 13:45:06 +08:00
    @Sunyanzi 确实没有开启 E_DEPRECATED ,开启后可以看到提醒。

    不过弃用提醒并不影响代码的执行,我其他关于 scope 的回答是针对 13 楼楼主问 test_global_ref 执行后 $obj 为什么仍然是 NULL ,与 Assigning the return value of new by reference 这个特性被弃用无关,可以把 &new stdClass 换作其他的类型,比如对一个字符串的引用。如果我这部分理解有误,希望可以给出正确的回答,我很愿意详细了解具体的缘由。
    haiyang416
        22
    haiyang416  
       2016-11-17 13:57:16 +08:00
    Zzzzzzzzz
        23
    Zzzzzzzzz  
       2016-11-17 14:15:35 +08:00
    php4 里赋值是复制, 所以才需要&load_class, php5 除了基本类型是写时复制外返回引用, 这种已经不用了.

    php5 没比 php4 晚发布多久, 但早期主要充当试验田, 社区想直接跨到 6 , 后来计划改了, 所以到了 5.2~5.3 期间才逐渐开始在生产环境铺开, 因此很多 php5 中早期产生的代码里会保留很多兼容 php4 的写法, 这种东西不用看了.
    jhdxr
        24
    jhdxr  
       2016-11-17 18:23:00 +08:00
    @silenceeeee 官方文档其实完全足以解释这个问题, 前提是你看懂了每一个字,参见: https://tech.jhdxr.com/archives/explanation-of-global-or-static-trap-in-php/
    jhdxr
        25
    jhdxr  
       2016-11-17 18:29:50 +08:00
    @Sunyanzi @Zzzzzzzzz 那段示例代码之所以会报错只是因为它的确使用了一个过时并且已经被移除了的特性,然而关于 global/static 的原理到现在(PHP 7)也依然没有变化。 此外, global 目前的确一般情况不再使用,但 static 还是丢不掉的。。。
    NoobPhper
        26
    NoobPhper  
       2016-11-17 20:01:52 +08:00
    楼主引用和引用计数要分开
    silenceeeee
        27
    silenceeeee  
    OP
       2016-11-17 20:04:42 +08:00 via iPhone
    @jhdxr 你说的这个我早就看懂了 就如你博客中说的一样 这个层面其实好理解 问题在于对象赋值与对象引用赋值 你去看下官方文档中对象与引用相关内容 如果有人愿意探讨这个问题可以与我电话联系 感觉码子效率太慢。很难表述 我个人感觉是理解不了这个问题了
    silenceeeee
        28
    silenceeeee  
    OP
       2016-11-17 20:48:41 +08:00 via iPhone
    @NoobPhper 引用计数指的是?
    NoobPhper
        29
    NoobPhper  
       2016-11-17 21:31:22 +08:00
    @silenceeeee sorry 是我粗心了了 没仔细看,这道题无关 引用 与 static 关键字 ,其实更像单例模式或者就是单例模式。
    obj2 和 obj1 用的是同一个被实例化的类。 你可以 var_dump $obj 来看 可以看到类似这样的状态

    ```
    /Users/laputa/Desktop/pattern/static.php:24:
    class a#1 (1) {
    public $a =>
    int(5)
    }
    5
    /Users/laputa/Desktop/pattern/static.php:31:
    class a#1 (1) {
    public $a =>
    int(1)
    }
    ```

    a# 后面的数字是在同一生命周期下被实例化的对象个数 同时也可以认为是标记 ,从同一个 1 可以看出 他们引用的是同一实例化对象 . 希望能帮到你
    NoobPhper
        30
    NoobPhper  
       2016-11-17 21:32:58 +08:00
    @silenceeeee 对你误导了 是在对不起
    jhdxr
        31
    jhdxr  
       2016-11-17 22:48:34 +08:00
    @silenceeeee 你先定义一下『对象赋值』与『对象引用赋值』
    lisir
        32
    lisir  
       2016-11-18 10:28:35 +08:00
    如果觉得饶了,可以看看这个(很清楚明了的): http://www.jb51.net/article/51985.htm
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   876 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 21:52 · PVG 05:52 · LAX 14:52 · JFK 17:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.