I'm looking for a way to access the default value assignment for a property without instantiating the class.
E.g.
class Foo {
private $bar = 'bar';
}
$reflClass = new ReflectionClass('Foo');
$reflProp = $reflClass->getProperty('bar');
Now what? If I use $reflProp->getValue() (without an object argument) it will fail.
You can use getDefaultProperties():
var_dump($reflClass->getDefaultProperties());
Related
I have just learned that you can set any property of a class (as long as it's not explicitly declared as a private one). For example:
class Test {}
$test = new Test;
$test->randomthing = 'Hello world';
var_export($test);
Works just fine to set the property randomthing of the $test object.
I am trying to find out what this behaviour is called, and if it's possible to eliminate/disable it (to minimise errors in code), because as it currently stands, i can be typoing my desired properties and not notice in time.
Ideally, i would want to have:
class User {
protected $name;
}
And then i want to be able to set a $user->name = '', but not $user->randomthing = ''. This second call would ideally throw an exception or something.
I have tried to guess this convention by looking up "dynamic properties", but that seems to refer to stuff like the double-dollar syntax to reference a property by a value in a variable.
So, what do you call this behaviour? And where can i read up more about controlling it (or disabling it)?
It doesn't have a special name or anything, it's just assigning a property to an object. This is standard and default PHP - to my knowledge, this isn't something you can disable/turn off.
All we're doing $object->newProp = 'foo' is appending a new key with a value to the object, that key + value pair isn't globally available once it's been added. It's only for that object. It's the same principle for an array:
$array = [1, 2, 3];
$array[] = 4;
We're doing the same with your object:
$object = new Class();
$object->foo = 4;
I would create a "magic" __set() function that doesn't set a parameter, but instead returns an error/warning.
public function __set ( string $name , mixed $value ) {
if( in_array( $name, [ 'various', 'valid', 'properties' ] ) ) {
$this->$name = $value;
} else {
trigger_error( "Setting unknown property ".__CLASS__."->$name is not permitted." );
}
}
https://www.php.net/manual/en/language.oop5.overloading.php#object.set
I have the following issue:
The current code of an application I'm working on contains a very large number of definitions like this:
$obj = new stdClass();
$obj->a->b = "something";
This results in: PHP Strict Standards: Creating default object from empty value in [somewhere].
The correct form would be:
$obj = new stdClass();
$obj->a = new stdClass();
$obj->a->b = "something";
Now the problem: Replacing this throughout the code would take ages (consider thousands of cases, with conditions, etc.).
So I was thinking of replacing stdClass with a custom object (this would be a simple replace in code), creating a setter for it that verifies if the variable property is an object, and defines it as object if it is before setting the second property.
So we get:
class MockObject() {
public function __set($property, $value) {
// Do stuff here
}
}
$obj = new MockObject();
$object->a->b = "something";
The problem is that when executing $object->a->b = "something"; setter is not called (because you don't actually set the a property, but the b property).
Is there any way around this? Or is other solution possible?
Note: Explicitly calling the __set() method is not a solution since it would be the same as defining properties as stdClass().
You know about the magic setter.
Use a magic getter also.
If it wants to get a var that does not exists: create one (in an array or something like that) that is an instance of that class.
Why don't you initialize your b variable in the constructor of the A class ?
public function __construct()
{
$this->b = new B();
}
I'm creating global setters and getters for my parent class since I don't want to create them for each child class variable (but I will occasionally overwrite the parent global setter / getter).
I'm using __call with it and I'm parsing the method name like this:
if (strtolower(substr($method, 0, 3)) == "set") {
$variable = strtolower(substr($method, 3));
}
The question is how can I check if the $variable is set for the child class (the one that is extending the main one);
If I do:
if ($this->$variable)
I suppose it first check if it exists on the child class and then it checks if it exists on the main class. I want it only to check the child class, is this possible to do?
I know there's parent:: but is there an equivalent for child?
EDIT:
People are not understanding what I'm asking.
I know how to check if the property exists. What I want to know is how to check if the property exists for the CHILD class, not for the MAIN class.
(class CHILD extends MAIN)
In common case there's isset() function, but is will not fit this case. Use property_exists() instead:
class Foo
{
public $pub = null;
}
$obj = new Foo();
var_dump(isset($obj->pub), property_exists('Foo', 'pub')); //false, true
-that's because if proprty exists, but is null, isset() will return false - and you'll not be able to differ the case, when it does not exist.
If it's about dynamic properties - then you should pass object and not class name to property_exists() since property may absent in class and then dynamically added to object.
Now, if we're saying about which class is declaring property, you can use Reflection in PHP, like this:
class Foo
{
public $pub = null;
}
class Bar extends Foo
{
}
$obj = new Bar();
$ref = new ReflectionObject($obj);
var_dump($ref->getProperty('pub')->getDeclaringClass()->getName() == 'Bar');//false
var_dump($ref->getProperty('pub')->getDeclaringClass()->getName() == 'Foo');//true
Why don't you make use of isset ??
if (isset($this->$variable))
This works for me:
if(property_exists($get_class($this),$variable)){}
Assume this class code:
class Foo {
function method() {
echo 'works';
}
}
Is there any way to store a reference to the method method of a Foo instance?
I'm just experimenting and fiddling around, my goal is checking whether PHP allows to call $FooInstance->method() without writing $FooInstance-> every time. I know I could write a function wrapper for this, but I'm more interested in getting a reference to the instance method.
For example, this pseudo-code would theoretically store $foo->method in the $method variable:
$foo = new Foo();
$method = $foo->method; //Undefined property: Foo::$method
$method();
Apparently, as method is a method and I'm not calling it with () the interpreter thinks I'm looking for a property thus this doesn't work.
I've read through Returning References but the examples only show how to return references to variables, not methods.
Therefore, I've adapted my code to store an anonymous function in a variable and return it:
class Foo {
function &method() {
$fn = function() {
echo 'works';
};
return $fn;
}
}
$foo = new Foo();
$method = &$foo->method();
$method();
This works, but is rather ugly. Also, there's no neat way to call it a single time, as this seems to require storing the returned function in a variable prior to calling it: $foo->method()(); and ($foo->method())(); are syntax errors.
Also, I've tried returning the anonymous function directly without storing it in a variable, but then I get the following notice:
Notice: Only variable references should be returned by reference
Does this mean that returning/storing a reference to a class instance method is impossible/discouraged or am I overlooking something?
Update: I don't mind adding a getter if necessary, the goal is just getting a reference to the method. I've even tried:
class Foo {
var $fn = function() {
echo 'works';
};
function &method() {
return $this->fn;
}
}
But from the unexpected 'function' (T_FUNCTION) error I'd believe that PHP wisely doesn't allow properties to store functions.
I'm starting to believe that my goal isn't easily achievable without the use of ugly hacks as eval().
It is. You have to use an array, with two values: the class instance (or string of the class name if you are calling a static method) and the method name as a string. This is documented on the Callbacks Man page:
A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1.
Demo (Codepad):
<?php
class Something {
public function abc() {
echo 'called';
}
}
$some = new Something;
$meth = array($some, 'abc');
$meth(); // 'called'
Note this is also works with the built-ins that require callbacks (Codepad):
class Filter {
public function doFilter($value) {
return $value !== 3;
}
}
$filter = new Filter;
$test = array(1,2,3,4,5);
var_dump(array_filter($test, array($filter, 'doFilter'))); // 'array(1,2,4,5)'
And for static methods -- note the 'Filter' instead of an instance of a class as the first element in the array (Codepad):
class Filter {
public static function doFilter($value) {
return $value !== 3;
}
}
$test = array(1,2,3,4,5);
var_dump(array_filter($test, array('Filter', 'doFilter'))); // 'array(1,2,4,5)'
// -------- or -----------
var_dump(array_filter($test, 'Filter::doFilter')); // As of PHP 5.2.3
Yes, you can. PHP has a "callable" pseudo-type, which is, in fact, either just a string or an array. Several functions (usort comes to mind) accept a parameter of the "callback" type: in fact, they just want a function name, or an object-method pair.
That's right, strings are callable:
$fn = "strlen";
$fn("string"); // returns 6
As mentioned, it's possible to use an array as a callback, too. In that case, the first element has to be an object, and the second argument must be a method name:
$obj = new Foo();
$fn = array($obj, "method");
$fn(); // calls $obj->method()
Previously, you had to use call_user_func to call them, but syntax sugar in recent versions make it possible to perform the call straight on variables.
You can read more on the "callable" documentation page.
No, as far as I know it's not possible to store a reference to a method in PHP. Storing object / class name and a method name in an array works, but it's just an array without any special meaning. You can play with the array as you please, for example:
$ref = [new My_Class(), "x"];
// all is fine here ...
$ref();
// but this also valid, now the 'reference' points to My_Other_Class::x()
// do you expect real reference to behave like this?
$ref[0] = new My_Other_Class();
$ref();
// this is also valid syntax, but it throws fatal error
$ref[0] = 1;
$ref();
// let's assume My_Class::y() is a protected method, this won't work outside My_Class
$ref = [new My_Class(), 'y'];
$ref();
this is prone to error as you loose syntax checking due to storing the method name as string.
you can't pass reliably a reference to a private or a protected method this way (unless you call the reference from a context that already has proper access to the method).
Personally I prefer to use lambdas:
$ref = function() use($my_object) { $my_object->x(); }
If you do this from inside $my_object it gets less clunky thanks to access to $this:
$ref = function() { $this->x(); }
this works with protected / private methods
syntax checking works in IDE (less bugs)
unfortunately it's less concise
Why can I not do something like the following when I know that the property of myobject is going to be declared already:
define('title','boats');
myobject->title;
but this works:
myobject->boats
Is this even good practice?
You can't use
$myobject->title
as this is attempting to access the title property of your object. If this property does not exist, an error will be triggered.
You can use
$myobject->{title}
but I'd rather see you use a variable instead of a constant, eg
$title = 'boats';
echo $myobject->$title;
Ideally, you will know which property you want to access and use its name appropriately
$myobject->boats
Why can I not do something like the following when I know that the property of myobject is going to be declared already:
Probably because PHP expects you to call it with a method name. There are options, though:
<?php
define( 'METHOD', 'bar' );
class Foo {
public function bar( ) {
echo "Foo->bar( ) called.\n";
}
}
$foo = new Foo;
call_user_func( array( $foo, METHOD ) );
// or
$method = METHOD;
$foo->$method( );
EDIT: Ah, I seem to have misunderstood. My version is for calling methods of which the name is defined in a constant, whereas you were looking for a way of calling properties. Well, I'll leave it in here for future reference anyway.