php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65352 Method Closure::bind() can access private property of object
Submitted: 2013-07-29 04:39 UTC Modified: 2013-07-31 20:57 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:0 of 1 (0.0%)
From: seyferseed at mail dot ru Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 5.4.17 OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: seyferseed at mail dot ru
New email:
PHP Version: OS:

 

 [2013-07-29 04:39 UTC] seyferseed at mail dot ru
Description:
------------
Method Closure::bind() can access private property of object.

And modify it by reference. It is a violation of encapsulation.

See script for example. http://3v4l.org/JE0eX

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

class Foo
{
    private $bar = 'baz';
}

$reader = function & ($object, $property) {
    $value = & Closure::bind(function & () use ($property) { 
        return $this->$property; 
    }, $object, $object)->__invoke();

    return $value;
};

$foo = new Foo();
$bar = & $reader($foo, 'bar');
$bar = 'tab';

var_dump($foo);

Expected result:
----------------
Fatal error: Cannot access private property Foo::$bar in /in/JE0eX on line 8

Actual result:
--------------
Output for 5.4.0 - 5.5.1

object(Foo)#2 (1) {
  ["bar":"Foo":private]=>
  &string(3) "tab"
}

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-07-30 18:09 UTC] mail+php at requinix dot net
As noted in Closure::bind(),

"public static Closure Closure::bind ( Closure $closure , object $newthis [, mixed 
$newscope = 'static' ] )

newscope
The class scope to which associate the closure is to be associated, or 'static' to 
keep the current one. If an object is given, the type of the object will be used 
instead. This determines the visibility of protected and private methods of the 
bound object."

You changed the scope of the function to be that of inside $foo. Naturally it 
would have access to private members. If you don't want it to do that then omit 
newscope=$object.
 [2013-07-31 02:14 UTC] seyferseed at mail dot ru
But if i'm add this function to class Foo by code it in class, i can't access 
private property! And this is right. You say, that my Getter function used in 
Closure::bind() can change (like Setter) private property and this is right? 
I don't think so.

Example:

class Foo
{
    private $bar = 'baz';

    public function &getBar()
    {
		return $this->bar;
    }
}

$foo = new Foo();

$bar = $foo->getBar();
$bar = "tab";
echo $foo->getBar();

It's still "bar". And i don't know how i can change Private property of class by 
reference in this case. It will be wrong, if i can. 

And now i'm take my getter

public function &getBar()
    {
		return $this->bar;
    }

Put it in Closure::bind() and i can change Private property. This is really 
wrong.
If i can change it only in function, that binded to Closure::bind(), like

$value = & Closure::bind(function & () use ($property) {

        $this->property = "tab";
        return $this->$property; 
    }, $object, $object)->__invoke();

It's okay, becouse it statically inside Foo. 

But Client code can change Private property by reference! Is that right?
 [2013-07-31 02:19 UTC] seyferseed at mail dot ru
If i'm add & there

$bar = & $foo->getBar();
$bar = "tab";
echo $foo->getBar();

I really can change Private $foo to "tab". I'm so confused... 

I'm expected 
Fatal error: Cannot access private property

But by reference there is no error.

Maybe this is PHP "feature" and there is no bug.
 [2013-07-31 04:30 UTC] mail+php at requinix dot net
>$bar = $foo->getBar();
Simply making the function return by reference is not enough: you have to assign 
by reference too. Otherwise the function returns a reference, yes, but your 
assignment makes a copy. You need both of the &s.

http://php.net/language.references.return
The first note on the page says exactly that.

Your version with Closure::bind() had both. That's why it worked.

Resolved?
 [2013-07-31 04:39 UTC] seyferseed at mail dot ru
For PHP, yes, solved. But not for logic. I believe that to change the link to 
private property is very wrong. Should generate an error.
 [2013-07-31 04:54 UTC] mail+php at requinix dot net
Variable scope. With bind() you were creating a closure that executes in the scope 
of that class. That's what the third argument was about. It means the function can 
do anything that a normal member function could have done, like call private 
methods and access private variables.

As with reflection, with great power comes great responsibility. If you want to 
get the error then omit the third argument so the function remains in the scope 
you were executing in (ie, the global scope).
 [2013-07-31 10:49 UTC] seyferseed at mail dot ru
You tell me about scope, i'm understand what you mean. But in my example i can 
change private property not in scrope. This is not about reading property, this 
is about setting private without setter.

See examples. $bar not copy, bar link to private.

$foo = new Foo();
$bar = & $reader($foo, 'bar');
$bar = 'tab';

This is not in class scope, this is just reference (link) to private property, 
but i can change it. I think this is wrong!

And in this case too:

$bar = & $foo->getBar();
$bar = "tab";

I think changing private property by reference in any case, with bind() or not, 
wrong. This is violation of encapsulation.
 [2013-07-31 16:42 UTC] mail+php at requinix dot net
References deal with the actual values of variables, not the variables 
themselves. Access control deals with variables. When you create $bar as a 
reference to something - anything - the only thing that matters when 
changing its value is the scope of $bar.

Like a piece of paper. I write down where my buried treasure is on two 
pieces, put one in a safe and give the other to you. You can use yours to 
loot the treasure and replace it with your own. The fact that the other 
piece of paper is locked away somewhere is irrelevant.

But here isn't the best place for an in-depth explanation of references. 
Trust me when I say that what's going on isn't a bug and that plenty of 
other languages act exactly the same way. If you would like a real 
explanation then I suggest finding an online PHP group, forum, or mailing 
list, and asking there. Or even emailing me, I wouldn't mind.
 [2013-07-31 20:57 UTC] cataphract@php.net
-Status: Open +Status: Not a bug
 [2013-07-31 20:57 UTC] cataphract@php.net
Sorry, but your problem does not imply a bug in PHP itself.  For a
list of more appropriate places to ask for help using PHP, please
visit http://www.php.net/support.php as this bug system is not the
appropriate forum for asking support questions.  Due to the volume
of reports we can not explain in detail here why your report is not
a bug.  The support channels will be able to provide an explanation
for you.

Thank you for your interest in PHP.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu May 16 23:01:30 2024 UTC