I'm new to php and I have executed below code.
<?php
class my_class{
var $my_value = array();
function my_class ($value){
$this->my_value[] = $value;
}
function set_value ($value){
// Error occurred from here as Undefined variable: my_value
$this->$my_value = $value;
}
}
$a = new my_class ('a');
$a->my_value[] = 'b';
$a->set_value ('c');
$a->my_class('d');
foreach ($a->my_value as &$value) {
echo $value;
}
?>
I got below errors. What could be the error?
Notice: Undefined variable: my_value in C:\xampp\htdocs\MyTestPages\f.php on line 15
Fatal error: Cannot access empty property in C:\xampp\htdocs\MyTestPages\f.php on line 15
You access the property in the wrong way. With the $this->$my_value = .. syntax, you set the property with the name of the value in $my_value. What you want is $this->my_value = ..
$var = "my_value";
$this->$var = "test";
is the same as
$this->my_value = "test";
To fix a few things from your example, the code below is a better aproach
class my_class {
public $my_value = array();
function __construct ($value) {
$this->my_value[] = $value;
}
function set_value ($value) {
if (!is_array($value)) {
throw new Exception("Illegal argument");
}
$this->my_value = $value;
}
function add_value($value) {
$this->my_value = $value;
}
}
$a = new my_class ('a');
$a->my_value[] = 'b';
$a->add_value('c');
$a->set_value(array('d'));
This ensures, that my_value won't change it's type to string or something else when you call set_value. But you can still set the value of my_value direct, because it's public. The final step is, to make my_value private and only access my_value over getter/setter methods
First, don't declare variables using var, but
public $my_value;
Then you can access it using
$this->my_value;
and not
$this->$my_value;
To access a variable in a class, you must use $this->myVar instead of $this->$myvar.
And, you should use access identifier to declare a variable instead of var.
Please read the doc here.
As I see in your code, it seems you are following an old documentation/tutorial about OOP in PHP based on PHP4 (OOP wasn't supported but adapted somehow to be used in a simple ways), since PHP5 an official support was added and the notation has been changed from what it was.
Please see this code review here:
<?php
class my_class{
public $my_value = array();
function __construct( $value ) { // the constructor name is __construct instead of the class name
$this->my_value[] = $value;
}
function set_value ($value){
// Error occurred from here as Undefined variable: my_value
$this->my_value = $value; // remove the $ sign
}
}
$a = new my_class ('a');
$a->my_value[] = 'b';
$a->set_value ('c'); // your array variable here will be replaced by a simple string
// $a->my_class('d'); // you can call this if you mean calling the contructor
// at this stage you can't loop on the variable since it have been replaced by a simple string ('c')
foreach ($a->my_value as &$value) { // look for foreach samples to know how to use it well
echo $value;
}
?>
I hope it helps
Interesting:
You declared an array var $my_value = array();
Pushed value into it $a->my_value[] = 'b';
Assigned a string to variable. (so it is no more array) $a->set_value ('c');
Tried to push a value into array, that does not exist anymore. (it's string) $a->my_class('d');
And your foreach wont work anymore.
This way you can create a new object with a custom property name.
$my_property = 'foo';
$value = 'bar';
$a = (object) array($my_property => $value);
Now you can reach it like:
echo $a->foo; //returns bar
I realise this answer is not a direct response to the problem described by the OP, but I found this question as a result of searching for the same error message. I thought it worth posting my experience here just in case anybody is muddling over the same thing...
You can encounter the error in question as a result of a poorly formatted for loop over an associative array. In a fit of bone-headedness, I was using -> instead of => in my for statement:
foreach ($object->someArray as $key->$val) {
// do something
}
Of course, I should have had:
foreach ($object->someArray as $key=>$val) {
// do something
}
I confused myself at first, thinking the reported error was referring to the someArray property!
Related
I need to call an function that is part of an object. The following call works as one would expect:
$someobject = getobject();
$result = $someobject->somefunction->value();
However, I need the "somefunction" component to be a variable.
I have tried to do it like this:
$var = 'somefunction';
$result = '$someobject->' . $var '->value'();
This does not work, but I hope it conveys what I am looking for. I've also tried a lot of variations based upon call_user_func() – without finding a syntax that works.
I am running: PHP 7.2.24-0ubuntu0.18.04.3. Vanilla version for Ubuntu 18.04 LTS.
To access a property or method dynamically based on its name, you simply use one more $ sign than you would normally.
For example, if we have this object:
class Foo {
public $someproperty = 'Hello!';
public function somefunction() {
return 'Hello World';
}
}
$someobject = new Foo;
Then we can access the property normally:
echo $someobject->someproperty;
Or dynamically by name:
$var = 'someproperty';
echo $someobject->$var;
Similarly, we can access the method normally:
echo $someobject->somefunction();
Or dynamically by name:
$var = 'somefunction';
$result = $someobject->$var();
Note that your example is a bit confusing, because you talk about "accessing a function where one part is a variable", but all you're actually trying to do is access a property dynamically, and you then happen to be calling a method on the object stored in that property. So the part you've called somefunction is actually the name of a property.
Here's an example that looks a bit like yours, but with the names changed:
class A {
public $foo;
}
class B {
public function value() {
return 'Hello World';
}
}
$a = new A;
$a->foo = new B;
$propertyname = 'foo';
echo $a->$propertyname->value();
class Blueprint
{
public function method()
{
return 'placeholder';
}
}
$object = new Blueprint;
$method = 'method';
// this will output `placeholder`
echo $object->{$method}();
Hooray!
The following (two alternative valid syntaxes are produced for the second line) works as expected without producing any errors:
$foobar = 'somefunction';
$result = $someobject->$foobar->value();
$result = $someobject->{$foobar}->value();
The following:
$foobar = 'somefunction';
$result = $someobject->${foobar}->value();
also works (i.e. it produces the expected result), but it also produces this warning:
Warning: Use of undefined constant foobar - assumed 'foobar' (this will throw an Error in a future version of PHP) …
Many thanks to all that commented. In particular Duc Nguyen and Swetank Poddar. I think it was the comment by Duc Nguyen in combination with the following comment by Swetank Poddar that finally cracked it.
class Util_Model
{
/**
* Get model property by property name chain.
* Usage: Util_Model::get_prop($order, 'item', 'name')
*/
public static function get_prop()
{
$obj = func_get_arg(0);
$props = array_slice(func_get_args(), 1);
if (!is_object($obj)) {
throw new \InvalidArgumentException('First parameter must be an object');
}
foreach ($props as $prop) {
if (preg_match('/^(.*)\(\)$/', $prop, $matches)) {
$obj = call_user_func(array($obj, $matches[1]));
} else {
$obj = $obj->{$prop};
}
if (!is_object($obj)) {
break;
}
}
return is_object($obj) ? (string)$obj : $obj;
}
}
$obj->{$prop} i wonder the meaning of this line, why there is a brace here? and why there is no error when {$prop} is null.if you don't understand my question, leave something I will amend it.thanks!
$obj->{$prop} means that $obj is trying to access a property whose name is present in the variable $prop. I'll explain with an example
class A {
public $d;
public $e;
public $f;
function X() {}
function Y() {}
function Z() {}
}
$obj = new A();
$prop = 'X';
$propVar = 'f';
$obj->{$prop}();
$obj->{$propVar};
In the above code, $prop contains the value 'X', so function X will be invoked, likewise if it was containing values 'Y' or 'Z', they would be invoked. So the invocation of function can be decided at runtime depending on the value the variable contains.
As for the case when $prop is null, no object is being accessed, so the reference of object is returned instead and no error is thrown.
It's the preferred syntax when using Variable Variables when accessing object properties. In this example, the brackets aren't required, though. Their main purpose is to avoid ambiguity:
$obj = (object) array(
'foo' => array('key' => 123)
);
$access = array('key' => 'foo');
var_dump($obj->{$access['key']});//will dump array(key => 123)
var_dump($obj->$access['key']);//ambiguous
The latter is ambiguous, because PHP might take the statement to mean "convert $access to its string value (which is Array), access the property with that name, and get the index key from that value", or it could mean, access the property with the name you find under $access['key'].
Either way, this can be useful, your code is taking it too far. You calling methods like this is not a good idea.
A valid use-case could be when dealing with JSON encoded data, or a parsed XML DOM, where there are numeric keys, or keys like foo-bar, you can't write:
$obj->123;
$obj->foo-bar;//- is invalid
For these cases, you use the variable variable notation:
$keys = [123, 'foo-bar'];
foreach ($keys as $key)
echo $obj->{$key}, PHP_EOL;
Is there any way i can nullify all $this variables without assigning null line by line?
public function refresh(){
unset($this);
}
The unset does not work..
You can't unset($ths) while you're in $this; otherwise you'd end up nowhere.
$this->propertyA = $this->propertyB = $this->propertyC = NULL;
why you want to do this? simple unset your instance of the class you are working with, and everything inside is gone
$a = new SomeClass();
$a->someVar = "1";
$a->someOtherVar = "2";
unset($a);
but don't forget to create a new instance, if you want to continue $a
However, this will reset all values to their default value set in the property definition:
foreach (get_class_vars(get_class($this)) as $name => $def){
$this->$name = $def;
}
You can try looping through each field and unset them one by one. Like this:
function refresh() {
foreach($this as $key => $value) {
unset($this->$key);
}
}
NOTE: I can't test it now this code is untested.
Below is my code in php,and I am getting error:
Parse error: syntax error, unexpected '[' in /LR_StaticSettings.php on line 4
<?php
class StaticSettings{
function setkey ($key, $value) {
self::arrErr[$key] = $value; // error in this line
}
}
?>
I want to use statically not $this->arrErr[$key] so that I can get and set static properties without creating instance/object.
Why is this error? Can't we create static array?
If there is another way, please tell me. Thanks
You'd need to declare the variable as a static member variable, and prefix its name with a dollar sign when you reference it:
class StaticSettings{
private static $arrErr = array();
function setkey($key,$value){
self::$arrErr[$key] = $value;
}
}
You'd instantiate it like this:
$o = new StaticSettings;
$o->setKey( "foo", "bar");
print_r( StaticSettings::$arrErr); // Changed private to public to get this to work
You can see it working in this demo.
Your code doesn't define $arrErr as a static member variable. You should declare it as
<?php
class StaticSettings{
public static $arrErr = array();
function setkey($key,$value){
self::arrErr[$key] = $value;
}
}
?>
First, a quote from the ole' manual on ArrayAccess::offsetSet():
This function is not called in assignments by reference and otherwise indirect changes to array dimensions overloaded with ArrayAccess (indirect in the sense they are made not by changing the dimension directly, but by changing a sub-dimension or sub-property or assigning the array dimension by reference to another variable). Instead, ArrayAccess::offsetGet() is called. The operation will only be successful if that method returns by reference, which is only possible since PHP 5.3.4.
I'm a bit confused by this. It appears that this suggests that (as of 5.3.4) one can define offsetGet() to return by reference in an implementing class, thus handling assignments by reference.
So, now a test snippet:
(Disregard the absence of validation and isset() checking)
class Test implements ArrayAccess
{
protected $data = array();
public function &offsetGet($key)
{
return $this->data[$key];
}
public function offsetSet($key, $value)
{
$this->data[$key] = $value;
}
public function offsetExists($key) { /* ... */ }
public function offsetUnset($key) { /* ... */ }
}
$test = new Test();
$test['foo'] = 'bar';
$test['foo'] = &$bar; // Fatal error: Cannot assign by reference to
// overloaded object in
var_dump($test, $bar);
Ok, so that doesn't work. Then what does this manual note refer to?
Reason
I'd like to permit assignment by reference via the array operator to an object implementing ArrayAccess, as the example snippet shows. I've investigated this before, and I didn't think it was possible, but having come back to this due to uncertainty, I (re-)discovered this mention in the manual. Now I'm just confused.
Update: As I hit Post Your Question, I realized that this is likely just referring to assignment by reference to another variable, such as $bar = &$test['foo'];. If that's the case, then apologies; though knowing how, if it is at all possible, to assign by reference to the overloaded object would be great.
Further elaboration: What it all comes down to, is I would like to have the following method aliases:
isset($obj[$key]); // $obj->has_data($key);
$value = $obj[$key]; // $obj->get_data($key);
$obj[$key] = $value; // $obj->set_data($key, $value);
$obj[$key] = &$variable; // $obj->bind_data($key, $variable);
// also, flipping the operands is a syntactic alternative
$variable = &$obj[$key]; // $obj->bind_data($key, $variable);
unset($obj[$key]); // $obj->remove_data($key);
As far as has, get, set, and remove go, they're no problem with the supported methods of ArrayAccess. The binding functionality is where I'm at a loss, and am beginning to accept that the limitations of ArrayAccess and PHP are simply prohibitive of this.
What the manual is referring to are so called "indirect modifications". Consider the following script:
$array = new ArrayObject;
$array['foo'] = array();
$array['foo']['bar'] = 'foobar';
In the above script $array['foo'] = array(); will trigger a offsetSet('foo', array()). $array['foo']['bar'] = 'foobar'; on the other hand will trigger a offsetGet('foo'). Why so? The last line will be evaluated roughly like this under the hood:
$tmp =& $array['foo'];
$tmp['bar'] = 'foobar';
So $array['foo'] is first fetched by ref and then modified. If your offsetGet returns by ref this will succeed. If not you'll get some indirect modification error.
What you want on the other hand is the exact opposite: Not fetch a value by reference, but assign it. This would theoretically require a signature of offsetSet($key, &$value), but practically this is just not possible.
By the way, references are hard to grasp. You'll get lots of non-obvious behavior and this is especially true for array item references (those have some special rules). I'd recommend you to just avoid them altogether.
This does not work with ArrayAccess, you could add yourself a public function that allows you to set a reference to an offset (sure, this looks different to using array syntax, so it's not really a sufficient answer):
class Test implements ArrayAccess{
protected $_data = array();
public function &offsetGet($key){
return $this->_data[$key];
}
...
public function offsetSetReference($key, &$value)
{
$this->_data[$key] = &$value;
}
}
$test = new Test();
$test['foo'] = $var = 'bar';
$test->offsetSetReference('bar', $var);
$var = 'foo';
echo $test['bar']; # foo
$alias = &$test['bar'];
$alias = 'hello :)';
echo $var; # hello :)
Probably such a function was forgotten when ArrayAccess was first implemented.
Edit: Pass it as "a reference assignment":
class ArrayAccessReferenceAssignment
{
private $reference;
public function __construct(&$reference)
{
$this->reference = &$reference;
}
public function &getReference()
{
$reference = &$this->reference;
return $reference;
}
}
class Test implements ArrayAccess{
...
public function offsetSet($key, $value){
if ($value instanceof ArrayAccessReferenceAssignment)
{
$this->offsetSetReference($key, $value->getReference());
}
else
{
$this->_data[$key] = $value;
}
}
Which then works flawlessly because you implemented it. That's probably more nicely interfacing than the more explicit offsetSetReference variant above:
$test = new Test();
$test['foo'] = $var = 'bar';
$test['bar'] = new ArrayAccessReferenceAssignment($var);
$var = 'foo';
echo $test['bar']; # foo
$alias = &$test['bar'];
$alias = 'hello :)';
echo $var; # hello :)