Edit report at http://bugs.php.net/bug.php?id=55026&edit=1

 ID:                 55026
 Comment by:         rasmus at mindplay dot dk
 Reported by:        rasmus at mindplay dot dk
 Summary:            Access to protected/private members using reflection
 Status:             Open
 Type:               Feature/Change Request
 Package:            Reflection related
 Operating System:   Windows/Linux
 PHP Version:        5.3.6
 Block user comment: N
 Private report:     N

 New Comment:

Okay, I guess I jumped the gun on this one - it turns out, this is possible, 

using the setAccessible() method.



http://de3.php.net/manual/en/reflectionproperty.setaccessible.php



So the following does work:



  $property = new ReflectionProperty('Foo', 'bar');

  $property->setAccessible(true);

  var_dump($property->getValue($object)); // does work



It appears that ReflectionMethod::setAccessible() was also added in 5.2 to the 

same end.



I believe it's a good thing to have to be very explicit about this in your code 

- having to indicate that you've understood what you're doing. Praise to 
whoever 

came up with that solution - it's actually better than what C# and others are 

doing.



However, the documentation is somewhat misleading:



"Sets a property to be accessible. For example, it may allow protected and 

private properties to be accessed."



I always understood this as meaning that it would actually change the 
visibility 

of an existing member - which would have been a rather destructive operation. 
It 

probably should more accurately read:



"Enables access to a protected or private property using the getValue() and 

setValue() methods, which would otherwise cause an exception."



In turn, the documentation for ReflectionProperty::getValue() and 

ReflectionProperty::setValue() needs to clarify this matter - something along 

the lines of:



"To enable access to private and protected properties, you must indicate your 

need to knowingly ignore the accessibility constraints of that property, by 

using the ReflectionProperty::setAccessible() method. Attempting to access a 

private or protected property without calling this method first, will cause an 

exception."



Similar documentation needs to be added for ReflectionMethod::setAccessible() 

and ReflectionMethod::invoke().


Previous Comments:
------------------------------------------------------------------------
[2011-06-10 15:36:32] rasmus at mindplay dot dk

Description:
------------
Allow me to preface by saying, I am aware of bug #40348. I believe you made a 
mistake when, as the other reporter put it, you "corrected" that "bug" - in the 
following, I will attempt to explain and cite evidence from other languages, 
and software implemented on other platforms.



The ReflectionProperty::getValue() and ReflectionProperty::setValue() methods 
don't work for protected and private properties - they work only for public 
members, which makes them redundant, since you can already use simple syntax 
like $object->{$propertyName} to access public members.



The ReflectionMethod::invoke() method also does not work for protected and 
private methods - again, this only works for public members, which you can 
already invoke in other ways, making this method redundant.



I believe the idea behind reflection, is to enable the implementation of 
popular meta-programming patterns. In order to do this, the language provides 
access to things that your programs would otherwise have no knowledge of, such 
as property-types, argument lists, etc.



Another important aspect of property and method reflection, is to facilitate 
access to protected and private members.



While the reflection-classes will enable you to find protected and private 
members, the current implementation leaves your program with the knowledge of 
these members, but being unable to perform any operations on them. This 
awareness of the internals of a class, unfortunately, is useless - there is no 
meaningful operation you can perform based on this information.



The idea of allowing access to protected/private members, may seem 
counter-intuitive at first, but it is necessary. With reflection, you provided 
access to information that was "private" to the internal interpretation of the 
source-code by the programming language itself. In much the same way, and for 
the same reasons, you need to provide access to private members of user code.



While, theoretically, you could write terrible, incomprehensible code, by 
giving yourself read/write access to any property of any object, this is of 
course not why this feature exists in other languages - it exists to facilitate 
good, clean meta-programming.



An object-relational mapper, for example, would likely need access to protected 
and private members, in order to persist them to the database. In programming 
languages like C# and Java, this is possible, and enables (for example) 
Hibernate (and NHibernate on .NET) to persist protected and private members to 
the database.



Another example is debugging and diagnostic components, which would likely need 
access to protected and private members - and preferably not by contrived 
means, such as are necessary at the moment.



To cite precedence, the following unit test passes in C#:



        class Foo

        {

            public Foo()

            {

                Bar = 123;

            }



            private int Bar { get; set; }

        }



        [Test]

        public void CanAccessPrivateMembers()

        {

            var test = new Foo();



            // test.Bar = 456; // this is private and inaccessible



            var property = test.GetType().GetProperty("Bar", 
BindingFlags.Instance | BindingFlags.NonPublic);



            Assert.AreEqual(123, property.GetValue(test, null), "access to 
private member Foo.Bar");

        }



By using reflection to access private members, the programmer enters into an 
agreement - he should have the understanding that things can wrong when this 
feature is not used responsibly.



Documentation for this feature should be clear about the fact that access to 
private members is only typically useful for meta-programming. For example, 
when you are enumerating the properties of an object, and making decisions 
based on other available metadata. Documentation should clarify that this 
feature should not be "abused" as a means to forcibly get access to a specific 
member, since that would defeat the purpose of having protected/private members 
in the first place.



In conclusion, the removal of this feature was a mistake - reflection in PHP is 
currently crippled, and not as useful as it is in other languages.

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



class Foo

{

  protected $bar = 123;

  

  protected function hello()

  {

    echo 'Hello, World';

  }

}



$object = new Foo;



var_dump($object);



$property = new ReflectionProperty('Foo', 'bar');



# var_dump($property->getValue($object)); // doesn't work



$method = new ReflectionMethod('Foo', 'hello');



# $method->invoke($object); // doesn't work



Expected result:
----------------
Both of the commented-out lines would cause the script to fail.



Uncommenting the first line, which should print '123', causes an exception.



Uncommenting the second line, should print 'Hello, World', but causes an 
exception.



Not demonstrated in this script is ReflectionProperty::setValue() which should 
also work.



Actual result:
--------------
Exceptions as described above.




------------------------------------------------------------------------



-- 
Edit this bug report at http://bugs.php.net/bug.php?id=55026&edit=1

Reply via email to