Having the following code
class test {
private $name;
public function __get($name){
return $name;
}
public function __set($name,$value){
$this->name = $value;
}
}
$obj = new test();
$obj->a = 2;
if (!empty($obj->a)) {
echo 'not empty';
}
This is calling __isset. But this is not being defined so it always return empty. What is the best way to check for a non empty property?
Update :changing the class is not a solution because it's a 3th party component and it has to remain intact.
If you can't change the class, I think the only possible workaround is using a temporary variable.
$obj->a = 2;
$test = $obj->a;
if (!empty($test)) {
echo 'not empty';
}
I know I am very late to the party here, however I am posting this for the edificationof any who may stumble across this question.
Firstly, I believe that the test class is wrong and if that is really what the 3rd party component does, I would chuck it out because it's rubbish. Do you really want all property names to map internally to the single property 'name', and thereby overwrite each other? Do you really want all property names to be returned as the property value? The code should look like this:
class test {
public function __get($name){
return $this->$name;
}
public function __set($name,$value){
$this->$name = $value;
}
}
Secondly, you can change the class, even if it has to remain intact. That's the point of inheritance. This is the open-closed principle. If the functions are incorrect, simply extend test like this to correct them:
class test {
private $name;
public function __get($name){
return $name;
}
public function __set($name,$value){
$this->name = $value;
}
}
class my_test extends test
{
public function __get($name)
{
return $this->$name;
}
public function __set($name,$value){
$this->$name = $value;
}
}
You shouldn't need to define __isset() as the corrected code will do what it is meant to do, but if you did you could do that here too.
Now the following will do what it is supposed to do (note the change of class name):
$obj = new my_test();
$obj->a = 2;
if (!empty($obj->a)) {
echo 'not empty';
}
change
public function __set($name,$value){
$this->name = $value;
}
To
public function __set($name,$value){
$this->$name = $value;
}
And then try
It does not make sense when used with anything other than the variable; ie empty (addslashes ($ name)) does not make sense, since it will be checked by anything other than a variable as a variable with a value of FALSE.
In your case, you should use the type conversion:
if ((bool)$obj->a) {
echo 'not empty';
}
Related
Is there a way to Override recursion limits for __get and __set on the same property. I want to be able to handle the second reentry differently than the first entry.
This code example isn't practical but the simplest to make the point.
class Foo {
public function __set($name,$value){
print "$name entered\n";
this->$name = $value; // want it to recurse here
}
}
$a = new Foo();
$a->baz = "derp";
print $a->baz;
// should get (cannot test at the moment)
// baz entered
// derp <- you get derp because the current php implementation creates an instance variable from the second call to __set
My Internet is down so I'm typing on my phone so typos are likely.
There's no way to do this with that syntax. Just call __set directly instead, e.g.:
class Foo {
public function __set($name, $value) {
print "$name entered\n";
$this->__set($name, $value);
}
}
I know this is a old question, but I think this is what you actually were looking for.
<?php
class Foo {
private $_data = array();
public function __set($name,$value){
print "$name entered\n";
$this->_data[$name] = $value;
}
public function __get($name){
if(array_key_exists($name, $this->_data)){
return $this->_data[$name];
} else {
return false;
}
}
}
$a = new Foo();
$a->baz = "derp";
print $a->baz;
?>
http://phpfiddle.org/main/code/4h0-an7
Please excuse me if this question has been asked before, but I tried searching for it with no satisfactory results.
I'm learning PHP (coming from a C++ background) and have come across the following ambiguity. The following two bits of code work exactly the same:
class A
{
public $myInteger;
public function __get($name)
{
return $this->$name;
}
public function __set($name, $value)
{
$this->$name = $value;
}
}
and
class A
{
public $myInteger;
public function __get($name)
{
return $this->name;
}
public function __set($name, $value)
{
$this->name = $value;
}
}
that is, in the class methods $this->$name and $this->name have the exact same function. I'm finding this a bit confusing, especially when considering that if you add the following code,
$myA = new A();
$myA->myInteger = 5;
$hereInt = $myA->myInteger;
echo "<p>" . $hereInt . "</p>";
it only works if there is no $ before myInteger. Could someone please explain the rationale behind this?
$this->$name and $this->name do not mean the same thing. The first is using a locally scoped variable $name to access the field of $this whose name is whatever $name contains, while the second accesses the name field directly.
For example, the following will output something:
$foo = new stdClass;
$foo->bar = 'something';
$baz = 'bar';
echo $foo->$baz;
In the case of __get and __set, $name contains the name of the property that was accessed at the call site; in your case, myInteger.
In your example, the __get and __set methods are actually superfluous, since $myA->myInteger is public and can be accessed directly. __get and __set are only needed to catch access attempts to a property that is not declared explicitly in the class.
For example, you might have a backing array that allows arbitrary "properties" to be set dynamically:
class Foo
{
private $_values = array();
public function __get($key)
{
if (isset($this->_values[$key]))
{
return $this->_values[$key]
}
}
public function __set($key, $value)
{
$this->_values[$key] = $value;
}
}
One thing that's somewhat confusing about this aspect of PHP's syntax is that a $ precedes a field declaration in a class, but there is none when accessing that field. This is compounded by the syntax for accessing static fields, which does require a $!
Ok i have a problem, sorry if i cant explaint it clear but the code speaks for its self.
i have a class which generates objects from a given class name;
Say we say the class is Modules:
public function name($name)
{
$this->includeModule($name);
try
{
$module = new ReflectionClass($name);
$instance = $module->isInstantiable() ? $module->newInstance() : "Err";
$this->addDelegate($instance);
}
catch(Exception $e)
{
Modules::Name("Logger")->log($e->getMessage());
}
return $this;
}
The AddDelegate Method:
protected function addDelegate($delegate)
{
$this->aDelegates[] = $delegate;
}
The __call Method
public function __call($methodName, $parameters)
{
$delegated = false;
foreach ($this->aDelegates as $delegate)
{
if(class_exists(get_class($delegate)))
{
if(method_exists($delegate,$methodName))
{
$method = new ReflectionMethod(get_class($delegate), $methodName);
$function = array($delegate, $methodName);
return call_user_func_array($function, $parameters);
}
}
}
The __get Method
public function __get($property)
{
foreach($this->aDelegates as $delegate)
{
if ($delegate->$property !== false)
{
return $delegate->$property;
}
}
}
All this works fine expect the function __set
public function __set($property,$value)
{
//print_r($this->aDelegates);
foreach($this->aDelegates as $k=>$delegate)
{
//print_r($k);
//print_r($delegate);
if (property_exists($delegate, $property))
{
$delegate->$property = $value;
}
}
//$this->addDelegate($delegate);
print_r($this->aDelegates);
}
class tester
{
public function __set($name,$value)
{
self::$module->name(self::$name)->__set($name,$value);
}
}
Module::test("logger")->log("test"); // this logs, it works
echo Module::test("logger")->path; //prints /home/bla/test/ this is also correct
But i cant set any value to class log like this
Module::tester("logger")->path ="/home/bla/test/log/";
The path property of class logger is public so its not a problem of protected or private property access.
How can i solve this issue? I hope i could explain my problem clear.
EDIT:
A simple demonstration
Modules::Name("XML_Helper")->xmlVersion ="Hello"; // default is 333
$a = Modules::Name("XML_Helper")->xmlVersion; // now $a should contain "Hello"
echo $a; // prints 333
What i need is
Modules::Name("XML_Helper")->xmlVersion ="Hello"; // default is 333
$a = Modules::Name("XML_Helper")->xmlVersion; // now $a should contain "Hello"
echo $a; // prints Hello
I realise you already said that path is public, but it's still worth mentioning: If you're using PHP 5.3.0+, note this quirk of property_exists():
5.3.0 | This function checks the existence of a property independent of
accessibility
In other words, if you check if (property_exists($delegate, $property)), you have no guarantee you have access to $delegate->$property for writing (or reading, for that matter, but you are trying to write).
As for actual troubleshooting: You could try checking if your if (property_exists($delegate, $property)) statement actually executes. If it doesn't, check the case of $property.
Sidenote: It's fairly hard to read the code you posted up, which makes it a bit of a pain to troubleshoot. Could you edit your post and indent it properly?
The path property of class logger is public so its not a problem of
protected or private property access.
That's your problem. From the docs:
__set() is run when writing data to inaccessible properties.
That suggests that __set() is not called for public properties.
I'm trying to get data from a class in php5, where the data in the class is private and the calling function is requesting a piece of data from the class. I want to be able to gain that specific piece of data from the private variables without using a case statement.
I want to do something to the effect of:
public function get_data($field)
{
return $this->(variable with name passed in $field, i.e. name);
}
You could just use
class Muffin
{
private $_colour = 'red';
public function get_data($field)
{
return $this->$field;
}
}
Then you could do:
$a = new Muffin();
var_dump($a->get_data('_colour'));
<?php
public function get_data($field)
{
return $this->{$field};
}
?>
You may want to look at the magical __get() function too, e.g.:
<?php
class Foo
{
private $prop = 'bar';
public function __get($key)
{
return $this->{$key};
}
}
$foo = new Foo();
echo $foo->prop;
?>
I would be careful with this kind of code, as it may allow too much of the class's internal data to be exposed.
Just an idea:
example (in PHP):
to set name:
$object->name('name');
to get name:
$object->name();
If no argument: the method is used as getter, else as setter. For simple getters/setter. Stupid, whatever, maybe?
edit: to follow up on the answers: I don't really like get and set because I prefer to have the interface as explicit as possible. When there are only a few properties it's also overkill IMHO. So I'd like to narrow it down to classes/objects with a couple of explicit getters/setters.
The problem is it would be hard to follow. I'd much rather use PHP5's __get and __set so it is more natural to get and set variables, and everyone would know exactly what I am doing. IE:
class myClass
{
function __get($name)
{
return $this->array[$name];
}
function __set($name, $value)
{
$this->array[$name] = $value;
}
function print()
{
echo $this->array['test'];
}
}
$obj = new myClass;
$obj->test = "Hi";
echo $obj->test; //echos Hi.
$obj->print(); //echos Hi.
It can be done using the __call() magic method.
class Test {
public function __call($name, array $args) {
$variable =& $this->$name;
if(!empty($args)) {
$variable = $args[0];
}
return $variable;
}
}
Sure, you could do that if it makes sense in your application, otherwise I would just use the standard getters/setters which have already been set up for you. Your function could look something like this:
public function name($val = null)
{
if (is_null($val))
{
return $this->name;
}
else
{
$this->name = $val;
}
}