I'm looking at Doctrine 2 and Symfony documentation for creating a model class.There are several code snippets where a getProperty and setProperty is used within the class, and these are somehow used automatically when a value is assigned directly to the property. This is different then the typical get/set magic methods, and the sample code I have come across does not implement any custom magic methods, so I believe this is handled by Doctrine somewhere.
From what I've read, Doctrine implements accessors and mutators. Maybe I missed a package when downloading Pear, or maybe I'm not including something in my script.
For example:
class User {
public $name;
public function getName()
{
// Do stuff
}
}
$user = new User();
$foo = $user->name; // getName is called
Note: I'm looking for a Doctrine specific solution. I know this can be done in someway with PHP, but I want to use Doctrine's native functions.
Edit: Updated to clarify how this differs from typical get/set magic methods, and note.
class User {
private $name;
public function __get($property) {
$methodName = "get".ucfirst($property);
if (method_exists($this, $methodName)) {
return call_user_func(array($this, $methodName));
} elseif (isset($this->{$property})) {
return $this->{$property};
}
return null;
}
public function __set($property, $value) {
$methodName = "set".ucfirst($property);
if (method_exists($this, $methodName)) {
call_user_func_array(array($this,$methodName), array($value));
} else {
$this->{$property} = $value;
}
}
public function getName() {
return "My name is ".$this->name;
}
}
$user = new User();
$user->name = "Foo";
$bar = $user->name;
echo $bar; // "My name is Foo"
If there is a method getSomething or setSomething it will be called when accessing the properties directly.
As I read in this documentation page, it is exactly what the code above does what Doctrine does. But it calls the method _set('fieldName', 'value').
If $name is declared public then this line of code:
$foo = $user->name;
is actually accessing the $name field, and is not in fact calling the getName function.
You can use PHP's magic __get and __set methods to automagically provide accessors and mutators, like this:
class User {
private $name;
public function __get($property) {
//check first to make sure that $property exists
return $this->$property;
}
public function __set($property, $value) {
//check first to make sure that $property exists
$this->$property = $value;
}
}
$user = new User();
$user->name = "Foo";
$bar = $user->name;
echo $bar; //"Foo"
You can find more info about PHP's magic methods here.
UPDATE: This is what I think Doctrine is doing:
class User {
private $name;
public function __get($property) {
$propertyTitleCase = mb_convert_case($property, MB_CASE_TITLE);
$method = "get{$propertyTitleCase}";
if(method_exists($this, $method))
{
return $this->$method();
}
else {
return $this->$property;
}
}
public function getName() {
//Do Stuff
}
}
Related
Is it possible in PHP 5.X to have a method in a class that is executed whenever a classes method is called, prior to the called function? I need this because i want to do some dynamic validation for the parameters used in the called function.
class MyClass {
protected function preHook(){ echo "You are about to call a method."; }
public function methodA() { echo "You called methodA."; }
}
$obj = new MyClass();
$obj->methodA();
// Output: "You called methodA."
// Desired output: "You are about to call a method.You called methodA"
Also keep in mind the following:
The "methodA" needs to be public because reflection is used in the code in order to detect the method.
As mentioned in comment this is impossible as __call magic method gets called only if method with given name is not defined:
http://php.net/manual/en/language.oop5.magic.php
However, maybe one of the following hackish solutions will solve your issue.
SOLUTION 1
will require changing all your methods names:
class MyClass {
public function __call($name, $arguments){
echo "You are about to call $name method.";
return call_user_func_array(array($this, '_real_' . $name), $arguments);
}
private function _real_methodA() { echo "You called methodA."; }
}
$obj = new MyClass();
$obj->methodA();
SOLUTION 2
this will require a 'wrapper' classes:
class MyClass {
public function methodA() { echo "You called methodA."; }
}
class MyClassWrapper {
public function __construct(){
$this->myClass = new MyClass();
}
public function __call($name, $arguments){
echo "You are about to call $name method.";
return call_user_func_array(array($this->myClass, $name), $arguments);
}
}
$obj = new MyClassWrapper();
$obj->methodA();
SOLUTION 3
Third approach would be to apply decorator pattern and create one wrapper class.
class Decorator
{
protected $_instance;
public function __construct($instance)
{
$this->_instance = $instance;
}
public function __call($method, $args)
{
print 'do your stuff here';
return call_user_func_array(array($this->_instance, $method), $args);
}
}
$obj = new Decorator(new MyClass);
$obj->methodA();
SOLUTION 4
mix of solution 1 and use reflection and "runkit_method_rename" to rename all methods
http://docs.php.net/manual/en/function.runkit-method-rename.php
runkit is experimental so this is rather hardcore.
class MyClass {
public function __call($name, $arguments){
echo "You are about to call $name method.";
return call_user_func_array(array($this, '_real_' . $name), $arguments);
}
private function methodA() { echo "You called methodA."; }
}
$reflection = new ReflectionClass('MyClass');
$methods = $reflection->getMethods();
foreach ($methods as $method) {
runkit_method_rename('MyClass', $method->name , '_real_' . $method->name);
}
$obj = new MyClass();
$obj->methodA();
In the end i modified the dispatcher to call the prehook (using __call in order to keep it hidden from reflection but still be public) before the actual method is called.
Assume we have this code:
class SomeClass{
private $somePrivateField;
public function __get($name){
$function = "get".ucfirst($name);
return $function;
}
public function __set($name,$value){
$function = "set".ucfirst($name);
return $function($value);
}
public function __call($name, $arguments) {
//if function being called is getSomething
//getThat private/protected field if exists and return
//if not raise exception
// similar for setSomething...
}
}
This is a passage from some tutorial:
The __get() method accepts an argument that represents the name of the property being set. In the case of $obj->property, the argument will be property.
Our __get() method then converts this to getProperty, which matches the pattern we defined in the __call() method. What this means is that $obj->property will first try to set a public property with the same name, then go to __get(), then try to call the public method setProperty(), then go to __call(), and finally set the protected $_property.
So when I say somewhere in my code
$obj->property
I can understand it tried to access the public field first..
Why does it go to __get() first? Why not __set() ?
Why does it go to __set() then?
Can someone please explain? Thanks...
__get() will only ever return a string comprising the name of a function that probably doesn't exist.
__set() actually calls the function whose name it constructs, but I'm having trouble determining why because...
__call() seemingly has to determine if the function it's calling is actually a "setter" or "getter" function, which is the entire point of __get() and __set() in the first place.
$obj->property is a non-sensical fragment of code that does not actually do anything on it's own.
// assuming $obj->property is declared as private, or does not exist in the class.
$var = $obj->property; // invokes __get('property')
$obj->property = $var; // invokes __set('property', $var)
$obj->someFunction($var1, $var2, ...);
// invokes __call('someFunction', array($var1, $var2, ...)), but only if
// the specified function is private, or otherwise does not exist.
To re-write the example code so that it makes some semblance of sense:
class SomeClass{
private $somePrivateField;
public function __get($name){
if( isset($this->$name) ) {
return $this->$name;
} else {
Throw new Exception("Object property $name does not exist.");
}
}
public function __set($name,$value){
if( isset($this->$name) ) {
$this->$name = $value;
} else {
Throw new Exception("Object property $name does not exist.");
}
}
}
$obj = new SomeClass();
$obj->somePrivateField = $var; // uses __set()
$var = $obj->somePrivateField; // uses __get()
Using __call() all is rarely necessary, certainly not for the given example.
Or if you would like to be able to set/get private/public properties without having to explicitly declare them first:
class SomeClass{
private $properties = array();
public function __get($name){
if( isset($this->properties['name']) ) {
return $this->properties['name'];
} else {
Throw new Exception("Object property $name does not exist.");
}
}
public function __set($name,$value){
$this->properties[$name] = $value;
}
// it's also a good idea to define __isset() and __unset() in this case as well
public function __isset($name) {
return isset($this->properties['name']);
}
public function __unset($name) {
return unset($this->properties['name']);
}
}
I have a class 'base' and a class 'loader', which looks like this.
class base {
protected $attributes = Array();
public $load = null;
function __construct() {
$this->load = loader::getInstance();
echo $this->load->welcome(); //prints Welcome foo
echo $this->load->name; //prints Foo
echo $this->name; //doesnt print anything and i want it to print Foo
}
public function __get($key) {
return array_key_exists($key, $this->attributes) ? $this->attributes[$key] : null;
}
public function __set($key, $value) {
$this->attributes[$key] = $value;
}
}
class loader {
private static $m_pInstance;
private function __construct() {
$this->name = "Foo";
}
public static function getInstance() {
if (!self::$m_pInstance) {
self::$m_pInstance = new loader();
}
return self::$m_pInstance;
}
function welcome() {
return "welcome Foo";
}
}
$b = new base();
Now what I want is a way to store variables from loader class and access them from base class using $this->variablename.
How can I achieve this? I don't want to use extends. Any idea ?
I don't feel like you've fully understood what coding the OOP way means. And usually Singletons are code smells so I'll just warn you:
There's probably a better way of accomplish you goal. If you provide more informations we will help you out. In its current form the answer is the following; just remember that I higly discourage its implementation in your code.
Assuming that you want to access only public (and non static) loader's variables as this->varname in the base class you should just insert this line in the beginning of the base class constructor:
$this->attributes = get_object_vars(loader::getInstance());
This will basically initialize the attributes array with all the loader public vars so that via your __get() method you can access its value.
On a side note, take a look at Dependency Injection design pattern in order to avoid using Singletons.
Your __get/__set methods access $this->attributes but not $this->load.
You could e.g. do something like (pseudocode)
function __get($key) {
- if $attribute has an element $key->$value return $attribute[$key] else
- if $load is an object having a property $key return $load->$key else
- return null;
}
see also: http://docs.php.net/property_exists
You can make static variable and then you can access this variable from anywhere
public statis $var = NULL;
and you can access it like this
classname::$var;
What would be the best practice to do this :
class AwesomeClass {
// Code
public function test()
{
foreach($objects->values as $v)
{
New SuperClass($v);
}
return $objects;
}
}
class SuperClass {
public function __construct($arg2)
{
return trim($arg2);
}
}
$rule_the_world = New AwesomeClass($arg1);
$king = $rule_the_world->test();
The previous code is obviously not working, I think I'm missing some major point of PHP OO.
It's very difficult to decipher what you're asking for, and the code you have is not recoverable.
Code Errors
There are several errors in your code that are illogical:
AwesomeClass has no constructor.
This makes passing arg1 to new AwesomeClass meaningless
arg1 is never initialized
In AwesomeClass::test(), objects is never initialized and has no member value.
You will get a warning since it's not traversable
New SuperClass (should be new, per standards) does nothing.
__construct() cannot return a value.
What You May Want
What I think you're going for is something like this:
class AwesomeClass implements IteratorAggregate {
private $arg1;
public function __construct(array $arg1) {
$this->arg1 = $arg1;
}
public function getIterator() {
return new ArrayIterator($this->arg1);
}
}
class SuperClass {
private $arg2;
public function __construct($arg2) {
$this->arg2 = $arg2;
}
public function __toString() {
return "$this->arg2\n";
}
}
$rule_the_world = new AwesomeClass(array('one', 'two', 'three'));
foreach ($rule_the_world as $sc) {
$sc = new SuperClass($sc);
echo $sc;
}
Note that it is redundant to create an ArrayIterator instance when arg1 must already be an array, this is just an example.
I am creating a __get() function for a class to control access to my private member variables. Do I need to design the function to handle all possible member value reads or can I not write it for members that are public? Also, I am assuming that classes that inherit this class will use my __get() function to access private members.
class ClassA{
private $collection = array();
public $value;
function __get($item){
return $collection[$item];
}
No, you don't.
class A {
public $foo = 'bar';
private $private = array();
public function __get($key) {
echo 'Called __get() at line #' ,__LINE__, ' with key {', $key ,'}',"\n";
return $this->private[$key];
}
public function __set($key, $val) {
$this->private[$key] = $val;
}
}
$a = new A();
var_dump($a->foo);
$a->bar = 'baz';
var_dump($a->bar);
And yes, it will:
class B extends A { private $private = array(); }
$b = new B();
var_dump($b->bar);
Well, your code would fail on private items not set in your array. But then again, you can use this as a way to deal with what's in and out of your array, as such ;
function __get($item){
if ( isset ( $collection[$item] ) )
return $collection[$item];
else {
try {
return $this->$item ; // Dynamically try public values
} catch (Exception $e) {
$collection[$item] = 0 ; // Make it exist
}
}
}
Classes that inherit your calls will use this __get(), but can be overridden, so use parent::__construct() for explicity. Also note that these cannot be static. Further reading.
First of all PHP searches for property name in class definition and tries to return its value. If there's no property - PHP tries to call __get($var) and here you can return anything you want. This is a little confusing behavior for those, who know Java-like getters/setters where you have to define them for every class member you want to access.
When it's comfortable to use Java-like getters/setters - you may write something like this:
public function __set($var, $value)
{
if (method_exists($this, $method = "_set_" . $var))
{
call_user_func(array($this, $method), $value);
}
}
public function __get($var)
{
if (method_exists($this, $method = "_get_" . $var))
{
return call_user_func(array($this, $method), $value);
}
}
and then use this code by defining custom getters/setters
protected function _get_myValue()
{
return $this->_myValue;
}
protected function _set_myValue($value)
{
$this->_myValue = $value;
}
and access to defined methods this way:
$obj->myValue = 'Hello world!';