php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #74776 undocumented change: PHP 7.1 preserves scope of call_user_func, breaks usage
Submitted: 2017-06-18 13:42 UTC Modified: 2018-07-08 22:36 UTC
From: iamonyourroof at gmail dot com Assigned:
Status: Verified Package: Documentation problem
PHP Version: 7.1.6 OS: Linux
Private report: No CVE-ID: None
 [2017-06-18 13:42 UTC] iamonyourroof at gmail dot com
Description:
------------
Dear,

the following code has a different output on php 7.0.20 vs php 7.1.0. 
It includes protected variables in the output, which is not what you would expect.

It seems like the scope for call_user_func has changed between these php versions.

If this change was on purpose, should it not have been documented as an item on the list of incompatible changes?
http://php.net/manual/en/migration71.incompatible.php

Test script:
---------------
<?php

    namespace crm;
 
 
     class et{
        protected $table = "b";
        public $field = "d";
        private $x = "private!";

       public function dump(){
         var_dump( call_user_func('get_object_vars', $this) );

       }

     }

     $et = new et();
     echo phpversion()."\n";
     $et->dump();

Expected result:
----------------
private/protected vars exposed

Actual result:
--------------
private/protected vars exposed on php version higher than 7.1

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-06-29 01:34 UTC] cmb@php.net
-Status: Open +Status: Verified -Assigned To: +Assigned To: dmitry
 [2017-06-29 01:34 UTC] cmb@php.net
It seems this behavioral change has been introduced with commit
6499162[1]. Therefore, I'm assigning to dmitry for clarification.

[1] <https://github.com/php/php-src/commit/6499162>
 [2017-06-29 10:20 UTC] dmitry@php.net
It seems the behavior was originally broken in PHP-7.0, when we introduced INIT_USER_CALL opcode. The same code without "namespace crm;" prints private/protected members in PHP-7.*, but not in PHP-5.*.

Now, in PHP-7.1 the behavior of call_user_func() in namespace is consistent with behavior outside namespace (however, this was made unintendedly).

We should fix this for both cases in PHP-7.0 and above (e.g. introduce ZEND_CALL_CALLBACK flag and disable call_user_func("internal_func",...) optimisation), or document the behavior change.

@nikic, what do you think?
 [2017-06-29 17:01 UTC] nikic@php.net
Note that this applies to all callbacks, e.g. also array_map: https://3v4l.org/FSHsW Interestingly it looks like HHVM is also using the PHP 7.1 behavior since version 3.19.

I don't have a strong opinion on what we should do here. The new behavior is consistent with callback visibility handling (you can call private methods with call_user_func, because the scope of the parent user function is used). I would be fine with just documenting this.

To execute a function in a clean scope, a simple way is to use a static closure, like so:

public function dump() {
    $getObjectVars = static function($object) { return get_object_vars($object); };
    var_dump($getObjectVars($this));
}
 [2017-07-03 07:05 UTC] dmitry@php.net
-Type: Bug +Type: Documentation Problem
 [2017-07-09 00:51 UTC] gmblar+php at gmail dot com
IMHO: Both calls should output the same. I don't expect that the scope changes if i use call_user_func.

var_dump(call_user_func('get_object_vars', $this));

var_dump(get_object_vars($this));
 [2017-08-14 13:50 UTC] dmitry@php.net
-Package: *General Issues +Package: Documentation problem -Assigned To: dmitry +Assigned To:
 [2018-07-08 22:36 UTC] cmb@php.net
Since variable functions “always” behaved this way[1], I think
this is a reasonable change.

[1] <https://3v4l.org/bL349>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Oct 13 11:01:28 2024 UTC