From:             
Operating system: Windows/Linux
PHP version:      5.3.6
Package:          Reflection related
Bug Type:         Feature/Change Request
Bug description:Access to protected/private members using reflection

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 bug report at http://bugs.php.net/bug.php?id=55026&edit=1
-- 
Try a snapshot (PHP 5.2):            
http://bugs.php.net/fix.php?id=55026&r=trysnapshot52
Try a snapshot (PHP 5.3):            
http://bugs.php.net/fix.php?id=55026&r=trysnapshot53
Try a snapshot (trunk):              
http://bugs.php.net/fix.php?id=55026&r=trysnapshottrunk
Fixed in SVN:                        
http://bugs.php.net/fix.php?id=55026&r=fixed
Fixed in SVN and need be documented: 
http://bugs.php.net/fix.php?id=55026&r=needdocs
Fixed in release:                    
http://bugs.php.net/fix.php?id=55026&r=alreadyfixed
Need backtrace:                      
http://bugs.php.net/fix.php?id=55026&r=needtrace
Need Reproduce Script:               
http://bugs.php.net/fix.php?id=55026&r=needscript
Try newer version:                   
http://bugs.php.net/fix.php?id=55026&r=oldversion
Not developer issue:                 
http://bugs.php.net/fix.php?id=55026&r=support
Expected behavior:                   
http://bugs.php.net/fix.php?id=55026&r=notwrong
Not enough info:                     
http://bugs.php.net/fix.php?id=55026&r=notenoughinfo
Submitted twice:                     
http://bugs.php.net/fix.php?id=55026&r=submittedtwice
register_globals:                    
http://bugs.php.net/fix.php?id=55026&r=globals
PHP 4 support discontinued:          http://bugs.php.net/fix.php?id=55026&r=php4
Daylight Savings:                    http://bugs.php.net/fix.php?id=55026&r=dst
IIS Stability:                       
http://bugs.php.net/fix.php?id=55026&r=isapi
Install GNU Sed:                     
http://bugs.php.net/fix.php?id=55026&r=gnused
Floating point limitations:          
http://bugs.php.net/fix.php?id=55026&r=float
No Zend Extensions:                  
http://bugs.php.net/fix.php?id=55026&r=nozend
MySQL Configuration Error:           
http://bugs.php.net/fix.php?id=55026&r=mysqlcfg

Reply via email to