Why I can not using $this with get_object_vars - php

<?php
require_once 'database.php';
class User {
public $id;
public $username;
public $first_name;
public $last_name;
public $password;
public static function find_by_id($id){
$result_array = self::find_by_sql("SELECT * FROM users WHERE id = {$id} LIMIT 1");
return !(empty($result_array))? array_shift($result_array): false;
}
public static function find_by_sql($sql){
global $database;
$result = $database->query($sql);
$object = array();
while ($row = $database->fetct_array($result)){
$object[] = self::instantiate($row);
}
return $object;
}
public static function instantiate($record)
{
$object = new self;
foreach($record as $attribute => $value)
{
if ($object->has_attribute($attribute)){
$object->$attribute = $value;
}
}
return $object;
}
private static function has_attribute($attribute){
$object_var = get_object_vars($this);
return array_key_exists($attribute, $object_var);
}
}
?>
I got error when I try to call function has_attribute. Notice: Undefined variable: this
Why I cannot use this in get_object_vars in private function has_attribute($attribute).
Can anyone help me with that?
Thank you.

$this is not defined in static methods (they belong to the class in general, not to specific object) - but all the methods in your class are defined as static.
You might want to change the has_attribute method so it'll take the instance of User as a param, but I don't think that's good design. In fact, I don't understand why do you need this method at all: for all the cases when non-existing property of an object is accessed, so-called magic method __get() is called automatically:
The overloading methods are invoked when interacting with properties
or methods that have not been declared or are not visible in the
current scope. [...] __get() is utilized for reading data from inaccessible properties.
If you defined has_attribute to prevent accessing non-existing properties (log these attempts, for example), move the code into __get.

That is because $this keyword is not accesible on a static context.
Source

Related

What is the use of return $this in php constructors?

I have always done :
class Class1{
protected $myProperty;
public function __construct( $property ){
$this->myProperty = $property;
}
}
But recently, I have been coming across a particular technique like so:
class Class2{
protected $myProperty;
public function __construct( $property ){
$this->myProperty = $property;
return $this;
}
}
And in instantiating this class, one would do :
$property = 'some value';
$class1 = new Class1( $property );
$class2 = new Class2( $property );
What is the significance of the line return $this in the constructor of Class2 since with or without it, the variable $class2 will still contain an instance of Class2?
Edit : please this is different from a constructor returning values. I heard this one is called fluent interfaces (for method chaining). I have looked at this thread Constructor returning value?. It is not the same thing I am asking. I am asking for the significance of return $this
There isn't a use for returning $this there.
Chances are that they are using a IDE which automatically inserts return $this or similar, which is useful for method chaining, but the return statement to __construct is discarded.
return $this; should not have any value in the constructor. But I see some value if it is returned in any other function for the class, when you want to call the functions consecutively. For example :
class Student {
protected $name;
public function __construct($name) {
$this->name = $name;
//return $this; (NOT NEEDED)
}
public function readBook() {
echo "Reading...";
return $this;
}
public function writeNote() {
echo "Writing...";
return $this;
}
}
$student = new Student("Tareq"); //Here the constructor is called. But $student will get the object, whether the constructor returns it or not.
$student->readBook()->writeNote(); //The readBook function returns the object by 'return $this', so you can call writeNote function from it.

PHP how to use magic method with static class? [duplicate]

This question already has answers here:
Magic __get getter for static properties in PHP
(6 answers)
Closed 9 years ago.
I'm trying to convert array to object. I want to use magic methods - __get and __set with static properties.
My code:
class UserData {
private static $id, $name, $login;
public function __get($var)
{
return self::$var;
}
public function __set($var, $val)
{
self::{$var} = $val;
}
}
And setting:
foreach($userArray as $key => $val)
{
DaneBilingowe::${$key} = $val;
}
Error:
Fatal error: Cannot access private property UserData::$id
Is it possible to use magic method with static property?
In short, no.
__get() and __set() are instance methods. They are essentially the functions that make up the stdClass(), which is an instance.
If you must set static content in this manner you can give the class a stdClass parameter and a singleton structure that would allow you to magically set and get data.
For example:
class UserData {
protected static $_instance;
protected $_data = array();
public static function get_instance() {
static $initialized = FALSE;
if ( ! $initialized) {
self::$_instance = new UserData;
$initialized = TRUE;
}
return self::$_instance;
}
public function __get($var) {
$self = self::get_instance();
return isset($self->_data[$var]) ? $self->_data[$var] : NULL;
}
public function __set($var, $val) {
$self = self::get_instance();
$self->_data[$var] = $val;
}
}
Then you could go:
$UserData =& UserData::get_instance();
$UserData->var = 'val';
echo $UserData->var; // prints 'val'
I don't recommend using Singletons in PHP, however, because they are pointless. You can read some reasons why in the post Best practice on PHP singleton classes.
Either use a static class or an instance class.
Magic getters and setters are shortcuts. You can implement the same behavior with normal setters and getters. The example below provides the same functionality, but the intent is a lot more clear:
class UserData {
protected $id, $name, $login;
public static function set_name($name) {
self::$name = $name;
}
public static function set_login($login) {
self::$login = $login;
}
public static function get_id() {
return self::$id;
}
public static function get_name() {
return self::$name;
}
public static function get_login() {
return self::login;
}
}
Notice how in the above code $id is not writable. It is only readable. $name and $login are readable and writable. It is easier and less buggy to control reading and writing using normal setters and getters. Magic methods are just that, magic, and usually magic is not concrete and is less understandable in code.
The final point I want to make is, why would UserData be static? Unless you only have 1 user in the entirety of your code it doesn't make sense to have it static. Perhaps I am not getting the whole picture, but something with an id and name should be instantiated so that you can have multiple instances. Otherwise, why have the id because the class itself is unique.
If you really want to use magic methods on static properties, you can but you will need an instance. Though it does not look reasonable, being a programmer itself is not reasonable at all :)
Also user defined classes and objects are not dynamic in php.
You can not add variables to them that easily... So you can use the pattern below:
class UserData {
private static $id, $name, $login, $arr = [];
public function __get($var){
return (array_key_exists(self::$arr, $var)? self::$arr[$var]:null;
}
public function __set($var, $val){
self::$arr[$var] = $val;
}
}
And setting: Well what is DaneBilingowe? I do not now here... But:
$inst = new UserData();
foreach($userArray as $key => $val){
$inst->$key = $val;
}
will work.
But beware, It will work only on class (static) memory.
Also since there is no appropriate filtering for setting names, weird things can happen.
(That means you should add them)

Not able to access private protect member in iterator php

Here is the data Iterator implementation
//Data Iterator
class DataIterator implements Iterator
{
public $data ;
public function __construct(Data $obj)
{
$this->data = $obj;
}
public function rewind()
{
$this->properties = get_object_vars($this->data);
}
public function valid()
{
if (key($this->properties) === null )
{
return false;
}
return true;
}
public function key()
{
return key($this->properties);
}
public function current()
{
return current($this->properties);
}
public function next()
{
next($this->properties);
}
}
and here is data class
/*Data Class*/
class Data implements IteratorAggregate
{
public $name;
private $age;
protected $address;
public $country;
public $state;
public function __construct($name, $age, $address, $country = 'USA', $state = 'NH')
{
$this->name = $name;
$this->age = $age;
$this->address = $address;
$this->country = $country;
$this->state = $state;
}
function getIterator()
{
return new DataIterator($this);
}
}
And here is the calling part
$data = new Data('Joker', '27', 'California');
foreach($data->getIterator() as $key => $value)
{
echo $key , ' ', $value, '<br>';
}
output
name Joker
country USA
state NH
Notice that the output does not contain my private and protected properties (age, address) output.
How do I tell Iterator to output those as well?
You cannot tell the iterator to output those properties because they are simply not accessible from the outside (i.e. the point where the iterator does get_object_vars($this->data).
There are two ways you could go about doing this:
By having the data object pass the values to the iterator.
Use the reflection API to pull them out by force (verbose, slow!).
But before going ahead with #1 as the preferred option, stop for a moment and ask yourself: why does the iterator expose non-public members of the data object?
Making something private means "You people don't really need to know about this; it may go away in the future, or it may change beyond recognition". If it's something that the outside world cares about, then why is it not public (either directly, or exposed through a public getter)? A rethink of what this iterator's purpose is might be in order.
That said, here's how you would do #1:
class DataIterator implements Iterator
{
public $data;
private $properties;
public function __construct(Data $obj, array $propeties)
{
$this->data = $obj;
$this->properties = $properties;
}
public function rewind()
{
// Arguably horrible trick to refresh the property map without
// demanding that Data exposes a separate API just for this purpose
$newIterator = $this->data->getIterator();
$this->properties = $newIterator->properties;
}
}
class Data implements IteratorAggregate
{
function getIterator()
{
return new DataIterator($this, get_object_vars($this));
}
}
Public, private and protected are access modifiers. They are designed to restrict the accessibility of your class attributes.
Public means that any one can access that attribute, so if someone wants, they can change the value, without that you know it.
Private mean that the attribute is only accessible INSIDE the class,
so nobody can "mess" with those properties from OUTSIDE the class.
Protected is similar like Private, but child classes (classes that
inherit from that class) have access to it.
You are making age and address private, so you are basically saying, nobody is allowed to access these attributes. If you want to access private/protected attributes, you will have to make getters and setters and call these functions, or make the attributes public.
try get_class_vars
$this->properties = get_class_vars(get_class($this->data));
instead of
$this->properties = get_object_vars($this->data);

How do I use objects and access their methods while within an object in PHP?

How do I use an object (along with its methods and properties) when I'm inside an object?
Say I have useless classes like these:
class Fruit {
private $name; // Name of the fruit.
private $health = 10; // 0 is eaten, 10 is uneaten.
private $object; // This is a PHP object.
public function __construct($name) {
$this->name = $name;
}
public function set($varname,$value) {
$this->$varname = $value;
}
}
class Eater {
private $name;
public function eat($object) {
$object->set('health',0); // I know I can pass and modify objects like this.
// The object is passed by reference in PHP5 (but not 4), right?
}
}
And I use it as such:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->eat($apple);
?>
But if I modify the Eater class like so:
class Eater {
private $name;
private $objectToEat; // Let's say if I need the object to be over here instead of in a method.
public function set($varname,$value) {
$this->$varname = $value;
}
public function eat() {
$this->objectToEat->set('health',0); // This doesn't work!
}
}
And set the main program like so:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->set('objectToEat',$apple);
$paul->eat();
?>
How can I access the object's properties from inside a method? I know I use $this->objectToEat to tell PHP I'm talking about the class properity, but since that property is an object, how do I access the object's methods?
I've tried $this->objectToEat->set('health',0) but that doesn't work. I hope you guys understand what I'm trying to get at (sorry, I can't figure out how to condense my question without compromising clarity)!
You have to set the property correctly. Since it's private, you can't do this from outside the object, so you have to use encapsulation:
class Eaters {
private $name;
private $objectToEat;
public function eat() {
$this->objectToEat->set('health',0); // Assumed "object" was just a typo
}
public function setObjectToEat($object) {
$this->objectToEat = $object;
}
}
Then use it like so:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->setObjectToEat($apple);
$paul->eat();
?>
Note: In this brief example, your original method is a better design. In certain cases, you might want to prime the method to be used by setting properties beforehand, but more often you want to call it with parameters directly, since it's more clear and more reusable (compartmentalized).
This answer modifies Renesis' answer
In the class, the object to eat is a private variable hence you can't go
$paul->objectToEat = $apple;
What you can do is to make a setter method inside Eaters
class Eaters {
private $name;
private $objectToEat;
public function eat() {
$this->objectToEat->set('health',0); // Assumed "object" was just a typo
}
public function setFood($object) {
$this->objectToEat = $object;
}
}
Therefore, you can call the setFood() method instead.
OR
Change eat() to
public function eat($object) {
$this->object->set('health',0);
return $object;
}
Saving the modified object back to the original variable.
OR
class Eaters {
private $name;
public function eat(&$object) { // this passes object by reference
$object->set('health', 0);
}
}
Although this code is not tested, that is how you can pass a variable by reference.
NOTE: You only need the & when defining the method not when you're passing an argument. For more info about Passing by Reference go to this link
It's probably because your eat method isn't accepting any parameters, and the Eaters class has no $object property.
Can you make $objectToEat a reference and then use it as such in the eat() function?
you have to set $this->object in class Eaters
function __construct($object){
$this->object = $object;
}
or
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->eat($apple);
?>
class Tester {
private $variable;
private $anObj;
public function testFn($val) {
$this->variable = $val;
$this->anObj = new SecondObj();
$this->doSomething();
}
public function doSomething() {
echo("My variable is set to " . $this->variable);
$this->anObj->wow();
}
}
class SecondObj {
public function __construct() {
echo("I'm new!");
}
public function wow() { echo("Wow!"); }
}
$tester = new Tester();
$tester->testFn(42);
Output:
I'm new!My variable is set to 42Wow!

Passing Objects into PHP constructor error

Is it possible to pass an object into the constructor of a PHP class, and set that object as a global variable that can be used by the rest of the functions in the class?
For example:
class test {
function __construct($arg1, $arg2, $arg3) {
global $DB, $ode, $sel;
$DB = arg1;
$ode = arg2;
$sel = $arg3;
}
function query(){
$DB->query(...);
}
}
When I try to do this, I get a "Call to a member function on a non-object" error. Is there anyway to do this? Otherwise, I have to pass the objects into each individual function directly.
Thanks!
You probably want to assign them to values on $this.
In your constructor, you'd do:
$this->DB = $arg1;
Then in your query function:
$this->DB->query(...);
This should similarly be done with the other arguments to your constructor.
$this in an instance context is how you reference the current instance. There's also keywords parent:: and self:: to access members of the superclass and static members of the class, respectively.
As a side-note...
Even thought this isn't required, it is generally considered best to declare member variables inside the class. It gives you better control over them:
<?php
class test {
// Declaring the variables.
// (Or "members", as they are known in OOP terms)
private $DB;
protected $ode;
public $sel;
function __construct($arg1, $arg2, $arg3) {
$this->DB = arg1;
$this->ode = arg2;
$this->sel = $arg3;
}
function query(){
$this->DB->query(...);
}
}
?>
See PHP: Visibility for details on the difference between private, protected and public.
you can do it pretty easily by storing the argument as a property of the object:
function __construct($arg1, $arg2, $arg3) {
$this->db = arg1;
}
function f()
{
$this->db->query(...);
}
let's say you have a db object
$db = new db();
and another object:
$object = new object($db);
class object{
//passing $db to constructor
function object($db){
//assign it to $this
$this-db = $db;
}
//using it later
function somefunction(){
$sql = "SELECT * FROM table";
$this->db->query($sql);
}
}

Categories