Getting protected information from an object in PHP - php

I'm pretty new to PHP and am trying to understand how to access properties of objects.
I have a class called Dog and in it's class I have the following:
class Dog extends Resource {
protected $_data = array(
'dog_id' => array(
'type' => Resource::PROPERTY_TYPE_INTEGER,
'value' => null
),
'owner_id' => array(
'type' => Resource::PROPERTY_TYPE_INTEGER,
'value' => null
)
)
}
Now I'm trying to use this data in a controller.
$drm = DogResouceModel::create();
$fido = array_values($drm->find($dog_id))[0];
This works and I get the desired Dog object as $fido. How would I get to the owner_id? Using XDebug in Eclipse I can see that the values are all attached to $fido, I just can't seem to figure out how to get to them. I've tried things along the lines of:
$owner_id = $fido["_data"]["owner_id"];
$owner_id = $fido->_data->owner_id;

The common way to do this is to implement getter/setter methods:
class Dog extends Resource
{
protected $data = [];//initialize as before (no need for the underscore)
public function getOwnerId()
{
return $this->data['owner_id']['value'];
}
//setter example
public function setOwnerId($id)
{
if (!is_numeric($id)) {
throw new InvalidArgumentException('Owner id is numeric');
}
$this->data['owner_id']['value'] = (int) $id;
return $this;
}
}
The rational behind this is that getters and setters allow you to validate data, normalize it and define, in greater levels of detail, how an object should behave if, for example, a value isn't available (ie: if owner_id is null, you might want to throw an exception in some cases).
The fact that you can see them in an XDebug session is simply because the data is set, and XDebug allows you to inspect the state of all objects. It doesn't follow the rules of inheritance in that it can see all values that are in play, regardless of them being private, protected or public. Xdebug is a PHP extension, it's written in C and sits on top of the Zend engine (the PHP internals), it is not bound by the syntax, grammar or whatever else that is part of PHP.
Think of Xdebug as an MRI scanner or X-ray machine: it allows you to see what is going on underneath the skin. It's a tool doctors use, like debuggers are tools that developers use to diagnose problems.
Looking at what you've tried, even if $data were public, neither approach would've worked:
$owner_id = $fido["_data"]["owner_id"];
The problem here is that this plies that $fido is an array, or an object that implements the ArrayAccess interface. We don't know what Resource looks like, so maybe it does (more on that later).
$owner_id = $fido->_data->owner_id;
This is closer to what you could do if _data were public, but only if its value were an object, too (which it isn't, it's an array).
So what should you write if $_data were public? Well simply this:
$ownerId = $fido->_data['owner_id']['value'];//to get the value
$ownerIdArray = $fido->_data['owner_id'];//will be an array
If Resource implements the ArrayAccess interface, chances are it relies on the $_data property, and returns the values for each key. In that case you might be able to write:
$ownerId = $fido['owner_id']
or even iterate over the object:
foreach ($fido as $propery => $value) {
//do stuff
}
Check the PHP documentation for details on the ArrayAccess interface

Because _data is protected, it's not possible to directly access it from outside the Dog or Resource classes. Instead, you should add an accessor to either Dog or Resource (as appropriate) that retrieves the requested data.
class Dog extends Resource {
public function getOwerId() {
return $this->_data['owner_id']['value'];
}
}
You could also force _data to be accessible by hacking it using the Reflection API, but that's really not something you should be doing on production code.

OOP Programming PHP
You are using OOP, grats dude (or dudette :P)!
PHP is great for this, however it has it's limitations, for example, accessing properties.
You have used protected $_data = array( /* your info */ );, this means it is only visible to the class and any class that extends this.
For example, if you had these classes:
class Foo
{
protected $foo = "Foo";
}
class Bar extends Foo
{
private $bar = "bar";
}
You could add a function, as such:
public function getFooBar()
{
return "{$this->foo} {$this->bar}";
}
Inside the Bar class, that simply returns the value of $foo and $bar, meaning if you use this code:
$bar = new Bar();
print $bar->getFooBar(); // prints "Foo bar"
But you cannot do this:
print $bar->foo;
print $bar->bar;
These are seen as private properties of the Bar class and as such cannot be accessed outside of the class.
When you use protected or private properties, if you need to access them outside the class, create a get function for them.
Why does the debugger show the private and protected properties?
When using a debugger such as XDebug, it is designed to show all properties within an object, this is so that the person debugging (you), can see exactly what's in an object and be able to create some sort of functionality to access this if needed. Without this, debugging tools would be rather useless.
I hope this helps you out :P

Related

PHP set magic method with array as names

I am creating a class which I will use to store and load some settings. Inside the class all settings are stored in an array. The settings can be nested, so the settings array is a multidimensional array. I want to store and load the settings using the magic methods __get and __set, so the settings can act as class members. However, since I'm using nested methods, I can't get the __set method to work when I try to access a nested setting.
The class is like this:
class settings
{
private $_settings = array();
//some functions to fill the array
public function __set($name, $value)
{
echo 'inside the __set method';
//do some stuff
}
}
And the code to use this class:
$foo = new settings();
//do some stuff with the class, so the internal settings array is as followed:
//array(
// somename => somevalue
// bar => array (
// baz = someothervalue
// qux = 42
// )
// )
$foo->somename = something; //this works, __set method is called correctly
$foo->bar['baz'] = somethingelse; //Doesn't work, __set method isn't called at all
How can I get this last line to work?
When accessing an array using this method, it actually goes through __get instead. In order to set a parameter on that array that was returned it needs to be returned as a reference: &__get($name)
Unless, what you mean is that you want each item that is returned as an array to act the same way as the parent object, in which case you should take a look at Zend Framework's Zend_Config object source for a good way to do that. (It returns a new instance of itself with the sub-array as the parameter).
This would work:
$settings = new Settings();
$settings->foo = 'foo';
$settings->bar = array('bar');
But, there is no point in using magic methods or the internal array at all. When you are allowing getting and setting of random members anyway, then you can just as well make them all public.
Edit after comments (not answer to question above)
Like I already said in the comments I think your design is flawed. Let's tackle this step by step and see if we can improve it. Here is what you said about the Settings class requirements:
settings can be saved to a file or a database
settings might need to update other parts of the application
settings need to be validated before they are changed
should use $setting->foo[subsetting] over $setting->data[foo[subsetting]]
settings class needs to give access to the settings data for other classes
first time an instance is made, the settings need to be loaded from a file
Now, that is quite a lot of things to do for a single class. Judging by the requirements you are trying to build a self-persisting Singleton Registry, which on a scale of 1 (bad) to 10 (apocalyptic) is a level 11 idea in my book.
According to the Single Responsibility Principle (the S in SOLID) a class should have one and only reason to change. If you look at your requirements you will notice that there is definitely more than one reason to change it. And if you look at GRASP you will notice that your class takes on more roles than it should.
In detail:
settings can be saved to a file or a database
That is at least two responsibilites: db access and file access. Some people might want to further distinguish between reading from file and saving to file. Let's ignore the DB part for now and just focus on file access and the simplest thing that could possibly work for now.
You already said that your settings array is just a dumb key/value store, which is pretty much what arrays in PHP are. Also, in PHP you can include arrays from a file when they are written like this:
<?php // settings.php
return array(
'foo' => 'bar'
);
So, technically you dont need to do anything but
$settings = include 'settings.php';
echo $settings['foo']; // prints 'bar';
to load and use your Settings array from a file. This is so simple that it's barely worth writing an object for it, especially since you will only load those settings once in your bootstrap and distribute them to the classes that need them from there.
Saving an array as an includable file isnt difficult either thanks to var_export and file_put_contents. We can easily create a Service class for that, for example
class ArrayToFileService
{
public function export($filePath, array $data)
{
file_put_contents($filePath, $this->getIncludableArrayString($data));
}
protected function getIncludableArrayString($data)
{
return sprintf('<?php return %s;', var_export($data, true));
}
}
Note that I deliberatly did not make the methods static despite the class having no members of it's own to operate on. Usign the class statically will add coupling between the class and any consumer of that class and that is undesirable and unneccessary.
All you have to do now to save your settings is
$arrayToFileService = new ArrayToFileService;
$arrayToFileService->export('settings.php', $settings);
In fact, this is completely generic, so you can reuse it for any arrays you want to persist this way.
settings might need to update other parts of the application
I am not sure why you would need this. Given that our settings array can hold arbitrary data you cannot know in advance which parts of the application might need updating. Also, knowing how to update other parts of the application isnt the responsiblity of a data container. What we need is a mechanism that tells the various parts of the application when the array got updated. Of course, we cannot do that with a plain old array because its not an object. Fortunately, PHP allows us to access an object like an array by implementing ArrayAccess:
class HashMap implements ArrayAccess
{
protected $data;
public function __construct(array $initialData = array())
{
$this->data = $initialData;
}
public function offsetExists($offset)
{
return isset($this->data[$offset]);
}
public function offsetGet($offset)
{
return $this->data[$offset];
}
public function offsetSet($offset, $value)
{
$this->data[$offset] = $value;
}
public function offsetUnset($offset)
{
unset($this->data[$offset]);
}
public function getArrayCopy()
{
return $this->data;
}
}
The methods starting with offset* are required by the interface. The method getArrayCopy is there so we can use it with our ArrayToFileService. We could also add the IteratorAggregate interface to have the object behave even more like an array but since that isnt a requirement right now, we dont need it. Now to allow for arbitrary updating, we add a Subject/Observer pattern by implementing SplSubject:
class ObservableHashMap implements ArrayAccess, SplSubject
…
protected $observers;
public function __construct(array $initialData = array())
{
$this->data = $initialData;
$this->observers = new SplObjectStorage;
}
public function attach(SplObserver $observer)
{
$this->observers->attach($observer);
}
public function detach(SplObserver $observer)
{
$this->observers->detach($observer);
}
public function notify()
{
foreach ($this->observers as $observers) {
$observers->update($this);
}
}
}
This allows us to register arbitrary objects implementing the SplObserver interface with the ObservableHashMap (renamed from HashMap) class and notify them about changes. It would be somewhat prettier to have the Observable part as a standalone class to be able to reuse it for other classes as well. For this, we could make the Observable part into a Decorator or a Trait. We could also decouple Subject and Observers further by adding an EventDispatcher to mediate between the two, but for now this should suffice.
Now to notify an observer, we have to modify all methods of the class that should trigger a notification, for instance
public function offsetSet($offset, $value)
{
$this->data[$offset] = $value;
$this->notify();
}
Whenever you call offsetSet() or use [] to modify a value in the HashMap, any registered observers will be notified and passed the entire HashMap instance. They can then inspect that instance to see whether something important changed and react as needed, e.g. let's assume SomeComponent
class SomeComponent implements SplObserver
{
public function update(SplSubject $subject)
{
echo 'something changed';
}
}
And then you just do
$data = include 'settings.php';
$settings = new ObservableHashMap($data);
$settings->attach(new SomeComponent);
$settings['foo'] = 'foobarbaz'; // will print 'something changed'
This way, your settings class needs no knowledge about what needs to happen when a value changes. You can keep it all where it belongs: in the observers.
settings need to be validated before they are changed
That one is easy. You dont do it inside the hashmap/settings object at all. Given that the HashMap is just a dumb container holding arbitrary data that is supposed to be used by other classes, you put the validation into those classes that use the data. Problem solved.
should use $setting->foo[subsetting] over $setting->data[foo[subsetting]]
Well, yeah. As you probably have guessed already, the above implementation doesnt use this notation. It uses $settings['foo'] = 'bar' and you cannot use $settings['foo']['bar'] with ArrayAccess (at least to my knowledge). So that is somewhat of a limitation.
settings class needs to give access to the settings data for other classes
This and the next requirement smell like Singleton to me. If so, think again. All you ever need is to instantiate the settings class once in your bootstrap. You are creating all the other classes that are required to fulfill the request there, so you can inject all the settings values right there. There is no need for the Settings class to be globally accessible. Create, inject, discard.
first time an instance is made, the settings need to be loaded from a file
See above.
The part $foo->bar is actually calling __get, this function should (in your case) return an array.
returning the right array in the __get would then be your solution.
As has been stated, this is because it is the array stored in $foo->bar that is being modified rather than the class member. The only way to invoke __set behaviour on an 'array' would be to create a class implementing the ArrayAccess interface and the offsetSet method, however this would defeat the purpose of keeping the settings in the same object.
A reasonably neat and common work around is to use dot delimited paths:
class Settings {
protected $__settings = array();
// Saves a lot of code duplication in get/set methods.
protected function get_or_set($key, $value = null) {
$ref =& $this->__settings;
$parts = explode('.', $key);
// Find the last array section
while(count($parts) > 1) {
$part = array_shift($parts);
if(!isset($ref[$part]))
$ref[$part] = array();
$ref =& $ref[$part];
}
// Perform the appropriate action.
$part = array_shift($parts);
if($value)
$ref[$part] = $value;
return $ref[$part];
}
public function get($key) { return $this->get_or_set($key); }
public function set($key, $value) { return $this->get_or_set($key, $value); }
public function dump() { print_r($this->__settings); }
}
$foo = new Settings();
$foo->set('somename', 'something');
$foo->set('bar.baz', 'somethingelse');
$foo->dump();
/*Array
(
[somename] => something
[bar] => Array
(
[baz] => somethingelse
)
)*/
This also makes it clearer you are not manipulating instance variables, as well as allowing arbitrary keys without fear of conflicts with instance variables. Further processing for specific keys can be achieved by simply adding key comparisons to get/set e.g.
public function set(/* ... */) {
/* ... */
if(strpos($key, 'display.theme') == 0)
/* update the theme */
/* ... */
}

Practical applications of PHP magic methods - __get, __set, and __call

I've generally tried to stay away from PHP's magic methods because they seem to obfuscate an object's public interface. That said, they seem to be used more and more, at least, in the code I've read, so I have to ask: is there any consensus on when to use them? Are there any common patterns for using these three magic methods?
The main reason is that you do not need to type as much. You could use them for, say, an ORM record and act as implicit setters/getters:
using __call():
$user = new User();
$user->setName("Foo Bar");
$user->setAge(42);
$user->save();
using __set():
$user->name = "Foo Bar";
$user->age = 42;
which maps to a simple array:
array(
"name" => "Foo Bar",
"age" => 42
)
It is much easier to write such an array to the database than doing a lot of manual calls to collect all needed information. __set() and __get() have another advantage over public members: You are able to validate/format your data.
__call()
I've seen it used to implement behaviors, as in add extra functions to a class through a pluginable interface.
Pseudo-code like so:
$method = function($self) {};
$events->register('object.method', $method);
$entity->method(); // $method($this);
It also makes it easier to write mostly similar functions, such as in ORMs. e.g.:
$entity->setName('foo'); // set column name to 'foo'
__get()/__set()
I've mostly seen it used to wrap access to private variables.
ORMs are the best example that comes to mind:
$entity->name = 'foo'; // set column name to 'foo'
It allows you to do things like this:
class myclass {
private $propertybag;
public function __get($name) {
if(isset($this->propertybag[$name]) {return $this->propertybag[$name];}
throw new Exception("Unknown property " . (string) $name);
}
}
Then you can populate $propertybag from a SQL query in a single line, rather than setting a whole bunch of properties one by one.
Also, it allows you to have specific properties which are read-only (ie don't allow them to be modified via __set()). Maybe useful for an ID field, for example.
Also, you can put code into __get() and __set(), so you can do something more complex than just getting or setting a single variable. For example, if you have a storeID field, you may also want to provide a storeName property. You could implement that in __get() via a cross-reference lookup, so you may not need the name actually to be stored in the class. And of course storeName would not want to be implemented in __get().
Lots of possibilities there.
There are of course some down-sides of using magic methods. The biggest one for me is the fact that you lose the auto-complete functionality in your IDE. This may or may not matter to you.
Since magic methods can save you a LOT of coding when it comes to repetitive tasks like defining members, populating them and then retrieving them - instead of doing that boring, long piece of work, you can use mentioned 3 methods to shorten the time to code all that. If needed, I can provide a few examples tho they can be found in various tutorials over the net.
I don't know if it's general consensus, but the usual should apply - use where appropriate. If you find yourself to do repetitive task (define member, populate member, get member, call X functions that differ slightly) - magic methods might help you.
One common pattern is to have a single handle for your clients and proxy the calls to encapsulated objects or singletons based on naming conventions or configurations.
class db
{
static private $instance = null;
static public function getInstance()
{
if( self::$instance == NULL )
self::$instance = new db;
return self::$instance;
}
function fetch()
{
echo "I'm fetching\n";
}
}
class dataHandler
{
function __call($name, $argv)
{
if( substr($name, 0, 4) == 'data' )
{
$fn = substr($name, 4);
db::getInstance()->$fn($argv);
}
}
}
$dh = new dataHandler;
$dh->datafetch('foo', 'bar');
Same principles can be used to drive different backends of the same functionality without having to change the driver.
Whenever you'd like, as long as the magic properties/methods are documented; undocumented magic should be avoided unless working with a very abstract layer of code, such as when developing an ORM.
acceptable at an abstract layer
/**
* DB backed model base class.
*/
class Model {
protected $attributes = [];
function __get($name) {
return #$this->attributes[$name];
}
}
acceptable when documented
/**
* User model backed by DB tables.
* #property-read string $first_name
* #property-read string $last_name
*/
class UserModel extends Model {
}
lazy and unacceptable (and common when using ORMs)
/**
* This class is magical and awesome and I am a lazy shithead!
*/
class UserModel extends WhoCaresWhenEverythingIsMagical {
}

PHP Overloading to Unit Test Private Properties and Methods

I've been reading here a few questions regarding the use of unit testing to test private methods and properties. I'm new to unit testing and would like input on the method I'm trying so that my testing can access private/protected properties and methods.
In the test I was working on I wanted to confirm that passing a particular parameter to the object resulted in a property being set. I'm using SimpleTest for my unit testing education and my test method is as follows:
function test__Construction_Should_Properly_Set_Tables() {
$cv = new CVObject( array( 'tables' => $this->standardTableDef ) );
$tables = $cv->tables;
$this->assertEqual( $tables, $this->standardTableDef );
}
Then I wrote a __get method in CVObject as follows:
function __get( $name ) {
$trace = debug_backtrace();
$caller = $trace[1];
$inTesting = preg_match( '/simpletest/', $caller['file'] );
if ( $inTesting ) {
return $this->$name;
} else {
trigger_error( 'Cannot access protected property CVObject::$' .
$name . ' in ' . $trace[0]['file'] . ' on line ' .
$trace[0]['line'],
E_USER_NOTICE );
}
}
My idea in this is that if the calling file is from SimpleTest, go ahead and make the property available for the testing purposes, but if not, trigger the error. This allows me to keep the property private but be able to use it in testing, which is going to be more important to me with a particular private method I'm about to begin writing.
So, my question is, am I missing something really bad here and should avoid this technique?
If you find yourself stuck and simply must access a private/protected property to enable thorough testing, at least place the code that enables access in your test or testing framework. Embedding testing-only code in production code a) complicates the design, b) adds more code that must be tested, and c) means the code runs differently in production.
You can use Ken's subclass method for protected properties, but if you need to access private and are on PHP 5.3.2+ you can use reflection.
function test__Construction_Should_Properly_Set_Tables() {
$cv = new CVObject( array( 'tables' => $this->standardTableDef ) );
$tables = self::getPrivate($cv, 'tables');
$this->assertEqual( $tables, $this->standardTableDef );
}
static function getPrivate($object, $property) {
$reflector = new ReflectionProperty(get_class($object), $property);
$reflector->setAccessible(true);
return $reflector->getValue($object);
}
Note that getPrivate() won't work as written for properties inherited from superclasses, but it's not too hard to loop up the hierarchy to find the declaring class.
While testing a component, you have to test only it's interface (input, output, exceptions), without considering or even knowing it's internal implementation (even better if one programmer writes test cases and the other does the implementation, please refer to XP and TDD techniques). So, the only thing you have to test are public methods.
To ensure, that your private (helper) methods are written correctly, simply use code coverage analyzer (please checkout Code Coverage tools for PHP) and cover as much code as possible with your test cases.
Your solution will guarantee you a maintenance nightmare. Test cases and component implementation should not be coupled in any way, because coupling would need to be bulletproof or otherwise you'll have to test it too.
A quick and dirty solution is to use protected (instead of private) methods, and then test using a wrapper that makes the methods under test public.
class Foo
{
protected function bar(){} // should really be private but protected will do
}
class FooTestWrapper extends Foo
{
public function bar{} { return parent::bar(); } // this is testable
}
But as ljank points out, testing private methods/implementation can become a maintenance nightmare - it probably means you are doing work that should be farmed out to other classes.
Generally speaking, your code should not contain features just for testing. And while it is debatable if testing private/protected methods is good practice, I find that sometimes and want to test a certain private/protected method in isolation.
Using Netsilik/BaseTestCase (MIT License) you can set/get private variable and call private or protected functions:
composer require netsilik/base-test-case
Class to test:
<?php
namespace App;
class Foo
{
private $bar;
protected function setBar(string $bar)
{
$this->bar = $bar;
}
}
Unit test:
class MyTestCase extends \Netsilik\Testing\BaseTestCase
{
public function test_whenProtectedMethodCalled_thenPrivateMemberSet()
{
$foo = new Foo();
self::callInaccessibleMethod($foo, 'setBar', 'abc');
self::assertEquals('abc', self::getInaccessibleProperty($foo, 'bar'));
}
}
Hope this helps.

What advantage is provided by object overloading in PHP?

PHP object overloading is explained here.
Basically it allows you to define some custom actions when an inaccessible object property or method is accessed.
What are some practical uses for this feature?
Usually, those methods are useful when you are communicating with a 3rd party API or when the method/members structure is unclear.
Let's say you are writing a generic XML-RPC wrapper. Since you don't know the methods available to you before you download the WDL file, it makes sense to use Overloading.
Then, instead of writing the following:
$xmlrpc->call_method('DoSomething', array($arg1, $arg2));
You can use:
$xmlrpc->DoSomething($arg1, $arg2);
which is a more natural syntax.
You can also use member overloading in the same way as method overloading for variable objects.
Just one thing you want to watch for: limit its use only to variable-structure objects or use it only for syntactical shortcuts to getters and setters. It makes sense to keep getters and setters in your class to seperate business logic in multiple methods, but there is nothing wrong in using it as a shortcut:
class ShortcutDemo {
function &__get($name) {
// Usually you want to make sure the method
// exists using method_exists, but for sake
// of simplicity of this demo, I will omit
// that logic.
return call_user_method('get'.$name, $this);
}
function __set($name, &$value) {
return call_user_method('set'.$name, $this, $value);
}
private $_Name;
function &getName() { return $this->_Name; }
function setName(&$value) { $this->_Name = $value; }
}
That way you can continue using your getters and setters to validate and set your data, and still use the syntactic shortcuts as such:
$shortcut->Name = 'Hello';
Another method that Andrew didn't mention (or hasn't mentioned at the time of writing) is for getting rid of getters and setters. Instead of having to declare each setter and getter like this:
$obj->setName("Chacha");
$obj->setRep(10000000000000000000000);
You can instead just do
$obj->Name = "chacha";
$obj->Rep = 100000000000000000;
The second method is more natural.
Magic Methods basically further the thought of Object Oriented programming, and the idea that how you implement a job should not matter to the outside world. Through Magic Methods, it allows you to store your variables however you want, and just let other classes set them in a natural way.
Example: I could store all my user's account preferences in a single array that would make it really easy to iterate through to push it all up to the session.
If I didn't use a Magic Method for this, I would either have to make a bunch of sets or gets, which means writing more code, or allow direct access to the array, which reveals the implementation, so I can't go and change it later.
Instead, using Magic Methods, I just have them set the variable regularly, and I deal with it internally.
You could use it for cases when a class has complex rules for isset and unset. For example, a class containing a variable $a could be an array of objects or other resources, and when unset, they have to do perform some other functionalities.
Though I am not sure why they allow the adding of a new property and retrieving of a non-private property, but you could use it to change the internal state of an object by calling other code depending on the name of the property/member variable being set.
In some cases, this resembles operator overloading in C++
Message forwarding for when you have composed or aggregated objects where polymorphism isn't an option (say, you're using a library class you can't control).
<?php
// Class A is final, so we can't make subclasses.
final class A
{
public function hello( $callback )
{
echo call_user_func( $callback, 'hello world' );
}
}
// so instead, we make a wrapper class that will take an instance
// of A as an aggregate
class B
{
private $a;
public function __construct( A $a )
{
$this->a = $a;
}
// this mimics inheritance on the aggregate object
// method calls are automatically forwarded to instance of A
// if they are valid
public function __call( $method, $args )
{
if ( method_exists( $this->a, $method ) )
{
return call_user_func_array( array( $this->a, $method ), $args );
}
throw new Exception( "Method [$method] not found." );
}
}
class C extends B
{
// This mimics overriding an "inherited" method
public function hello( $callback )
{
echo call_user_func( $callback, 'bonjour le monde' );
}
}
$a = new A;
$b = new B( $a );
$c = new C( $a );
$b->hello( 'strtoupper' );
$c->hello( 'strtoupper' );
This feature is actually what object oriented programming is all about, in the mind of its inventor Alan Kay: Objects sending each other messages, and potentially reacting to any kind of message. Methods fixed at compile time are a limited (but also more efficient) implementation of this concept. That's where Kay's famous-quote "I invented the term object oriented, and I can tell you that C++ wasn't what I had in mind." comes from.
Basically, allowing objects to react to method calls without having a corresponding method fixed at compile time implements this original, broader definition of object orientation. Most modern "dynamic" languages support it in one form or another.
As for what it's good for: take a look at Groovy's Builders for a good example. Basically, it allows very compact low-redundancy syntax by turning method names themselves into data.
One way, which is quite a bit fancier, that I've used it is to create a Linq like Object Relational Management (ORM) system. Where you can then load up a database table structure and manipulated the data (from the database table) as if it were just an object.
i.e.
include('blibrary/bLinq.class.inc');
$linq = new bLinq(new bLinqSql('mysql://dsn'));
$r = $linq->from('Users')
->password
->select();
which translates to the following SQL:
SELECT `password` from Users;
The password in the select statement comes from the overloaded method.
The result can be used like:
(array)$r->password; // which outputs an array multiple results of password;
(string)$r->password; // which outputs a string of the first password hash;
$r->password[2]; // which outputs a string of the third password hash;
The point is that the word "password" could be substituted for any other field in the database on the fly when programming.
I use __get and __set to link objects together e.g.
$user = new User();
echo $user->Profile->views;
This (usually) calls some SQL linking users.id = profile.user_id.
Properties (like that in Python or C#). For example when you use something like this in Nette, you create some class, which shows some property as public:
<?php
class Foo extends Object
{
public $bar;
}
You can access this property natural way – $instance->bar. But when you want to do some validation etc., you just add getter and setter:
<?php
class Foo extends Object
{
private $bar;
public function getBar()
{
return $this->bar;
}
public function setBar($bar)
{
if ($bar === NULL) throw new Exception('…');
$this->bar = $bar;
}
}
And still you use $instance->bar. But when you do $instance->bar = NULL;, it's like calling $instance->setBar(NULL);.

PHP Scope and Class Instance Interaction

It seems as though different instances of a class can know about each others' private member variables.
I have provided some code that attempts to showcase my issue, and I will try to explain it.
We have a class with a private member variable, $hidden. modifyPrivateMember sets the value of $hidden to 3. accessPrivateMember takes an Object as a parameter and accesses its private $hidden member to return its value.
Example code:
<?php
// example.php
class Object {
private $hidden;
public function modifyPrivateMember() {
$this->hidden = 3;
}
public function accessPrivateMember(Object $otherObject) {
return $otherObject->hidden;
}
}
$firstObject = new Object;
$firstObject->modifyPrivateMember();
$otherObject = new Object;
echo $otherObject->accessPrivateMember($firstObject);
Output of the above code:
$ php example.php
3
Can anyone explain why private members of objects are accessible to other instances of the same class? Is there some justification for this ostensible breach of scope?
private means it's restricted to only that class, not only that object.
That's just how php works. It's the same as how Java works. See http://php.net/manual/en/language.oop5.visibility.php for more info.
The only situation in which this behavior seemed useful was in a factory function:
class Object
{
private $state;
public static function makeObject()
{
$obj = new Object;
$obj->state = 'some state';
return $obj;
}
}
Even in this case, there are better solution and I agree with you that it is a breach of scope, although not that big in my opinion. After all, the one who writes the class decides if she needs to access private members from objects passed as arguments. So, it may seem useless (even to me), but you never know. It's not like you're exposing your internals to subclasses or something. It all happens in the same class and it's your business what you're doing in there.
By the way, one language that implements access modifiers per object and not per class is Ruby.

Categories