New to PHP.
I have created a simple class:
class User
{
private $name;
private $password;
private $email;
public function getName()
{
return $this->name;
}
public function setName($value)
{
$this->name = $value;
}
public function setPassword($value)
{
$this->password = $value;
}
public function setEmail($value)
{
$this->email = $value;
}
public function getEmail()
{
return $this->email;
}
}
I created 2 instances of this class and stored the first instance into an array. I am then checking to see if the second instance exists in the array (the one I did not add to the array). For some reason in_array() always returns '1' or true.
It turns out that the array now somehow contains the second user object that I did not explicitly add to the array. As if the properties of User are behaving like static class members. What am I missing?
$user = new User();
$user::setName('Nick');
$user::setEmail('bbbb#gmail.com');
$user::setPassword('bbbbb');
$somethingelse = new User();
$somethingelse::setName('Mindy');
$somethingelse::setEmail('a#gmail.com');
$somethingelse::setPassword('aaaa');
$arr = array('users'=>$user); //add first object to array
echo in_array($somethingelse,$arr); //check if second object is in array
echo $arr['users']::getName(); //Prints mindy
}
Because you're using the namespace resolution operator ::, rather than the instance dereferencing operator ->. The first invokes the method on the class, the second on an instance. If you turn on E_STRICT error reporting (which you should!), you'll see a bunch of warnings about calling instance methods statically.
To fix this, use $user->setName('Nick'); (with similar changes elsewhere).
use
->
instead of
::
In short, it’s used to access Static or Constant members of a class.
it would result in
$user = new User();
$user->setName('Nick');
$user->setEmail('bbbb#gmail.com');
$user->setPassword('bbbbb');
$somethingelse = new User();
$somethingelse->setName('Mindy');
$somethingelse->setEmail('a#gmail.com');
$somethingelse->setPassword('aaaa');
$arr = array('users'=>$user); //add first object to array
echo in_array($somethingelse,$arr); //check if second object is in array
echo $arr['users']->getName(); //Prints mindy
Related
I'm still new to OOP and this is probably a simple question, not sure if I'm overthinking this.
Let's say we have a simple class like the following that we can use to instantiate an object that can generate an array:
class gen_arr {
public $arr = array();
public function fill_arr() {
$this->arr["key"] = "value";
}
}
// instantiate object from gen_arr
$obj = new gen_arr();
Now if you wanted to get the value of the object's array's item, would you generate an array first and then echo the value like:
$arr = $obj->fill_arr();
echo $arr["key"];
Or would you access the object's property directly?
echo $obj->arr["key"]
In the actual code the property is private and there is a method that allows the viewing of the property array, the above is just to simplify the question.
Are there performance considerations and/or just best practices when it comes to this kind of case?
UPDATE:
It's still unclear from the answers if the best way is to generate an array from the property and access that array or just access the property directly (through the getter method)
Since you are filling the array with items only on fill_arr, those items wont be availabl until you call $arr = $obj->fill_arr();.
If you want to directly call the array, then you have to fill this array on the constructor function of this call like this:
class gen_arr {
public $arr = array();
function __construct() {
$this->arr["key"] = "value";
}
}
First off, the class you shared with us has a range of problems:
its sole instance property is public and can be modified by anyone
you have some temporal coupling, the method fill_arr() needs to be invoked before accessing the the value makes any sense
Encapsulation
Reduce the visibility of the instance property from public to private, so that the property can only be modified by the object itself, and provide an accessor instead:
class gen_arr
{
private $arr;
public function fill_arr()
{
$this->arr["key"] = "value";
}
public function arr()
{
return $this->arr;
}
}
Temporal Coupling
Remove the method fill_arr() and instead initialize the property $arr in one of the following options:
initialize field lazily when accessed the first time
initialize field in the constructor
initialize field with a default value
initialize field with a value injected via constructor
Initialize field lazily when accessed the first time
Initialize the field when it's accessed the first time:
class gen_arr
{
private $arr;
public function arr()
{
if (null === $this->arr) {
$this->arr = [
'key' => 'value',
];
}
return $this->arr;
}
}
Initialize field in the constructor
Assign a value during construction:
class gen_arr
{
private $arr;
public function __construct()
{
$this->arr = [
'key' => 'value',
];
}
public function arr()
{
return $this->arr;
}
}
Initialize field with a default value
Assign a value to the field directly, which works fine if you don't need to do any computation:
class gen_arr
{
private $arr = [
'key' => 'value',
];
public function arr()
{
return $this->arr;
}
}
Initialize field with a value injected via constructor
If the values are not hard-coded or otherwise calculated (as in the previous examples), and you need to be able to instantiate objects with different values, inject values via constructor:
class gen_arr
{
private $arr;
public function __construct(array $arr)
{
$this->arr = $arr;
}
public function arr()
{
return $this->arr;
}
}
Accessing and dereferencing values
This seems like this is your actual question, so the answer is - of course - It depends!.
Let's assume we have provided an accessor instead of accessing the otherwise public field directly:
Since PHP 5.4, the following is possible:
$object = new gen_arr();
echo $object->arr()['key'];
If you are still using an older version of PHP, you obviously can't do that and have to do something like this instead:
$object = new gen_arr();
$arr = $object->arr();
echo $arr['key'];
Largely, though, the answer to this question depends on the circumstances, and what you want to achieve. After all, readability is key for maintenance, so it might just make sense for you to introduce an explaining variable.
Note About your example, you could just use an ArrayObject instead:
$arr = new \ArrayObject([
'key' => 'value',
]);
echo $arr['key']);
For reference, see:
http://wiki.c2.com/?EncapsulationDefinition
http://blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling/
http://php.net/manual/en/language.oop5.properties.php
http://wiki.c2.com/?ItDepends
http://php.net/manual/en/migration54.new-features.php
https://refactoring.com/catalog/extractVariable.html
http://wiki.c2.com/?IntroduceExplainingVariable
http://php.net/manual/en/class.arrayobject.php
For an example, see:
https://3v4l.org/qVVBM
First fill up the array
$gen_arr = new gen_arr();
$gen_arr->fill_arr();
then get the values with a getter method
$val = $gen_arr->getValue($key);
A getter method would be like this
public function getValue($key) {
return $this->arr[$key];
}
And certailny make the $arr property private
What is the difference between assigning property values using a constructor and direct property assignment within the class declaration? In other words, what is the difference between the following two pieces of code making default values for the new object?
Code with direct assignment:
<?php
class A {
public $name="aName";
public $weight = 80;
public $age = 25;
public $units = 0.02 ;
}
?>
Code with constructor:
<?php
class A {
public $name;
public $weight;
public $age;
public $units;
public function __construct() {
$this->name = "aName";
$this->weight = 80;
$this->age = 25;
$this->units= 0.02 ;
}
}
?>
You may answer that i can't change the hard coded properties, but i could in the following code( In Local Sever ):
<?php
class A{
public $name="aName";
public $weight = 80;
public $age = 25;
public $units = 0.02 ;
}
class B extends A{
public function A_eat(){
echo $this->name.' '."is".' '.$this->age.' '."years old<br>";
echo $this->name.' '."is eating".' '.$this->units.' '."units of food<br>";
$this->weight +=$this->units;
echo $this->name.' '."weighs".' '.$this->weight."kg";
}
}
$b = new B();
echo "<p>If no changes to the object's Properties it inherits the main class's</p>";
$b->A_eat();
echo '<br><br>';
echo "<p>If changes made to the object's Properties it uses it's new properties</p>";
$b->name ="bName";
$b->weight = 90;
$b->units = 0.05;
$b->A_eat();
?>
When a property declaration contains initialization, the initialization is evaluated at compile time, i.e. in the step when the PHP source is compiled into PHP opcodes.
The code within constructor is evaluated at run time, i.e. at the time when one creates an object with new operator.
There is practically no difference, if you don't use opcode caching (OPcache, APC, and similar extensions). However, if the opcodes are cached, the performance will be better with the compile-time initialization, obviously.
Nothing really however,...
in the construct() you could pass in optional variables... for instance..
public function __construct($name = 'aName', $weight = 80, $age = 25, $units = 0.02) {
$this->name = $name;
$this->weight = $weight;
$this->age = $age;
$this->units = $units;
}
In the first example you posted, you are defining HARD values to your properties, where as in the 2nd one, the construct will let you "build" those...
Take the first example:
$x = new Class();
// You can't change it, those properties are what you coded in...
Now look at my example...
$x = new Class('My New Name', 120, 30, 0.10);
// Now $name = 'My New Name' etc...
The construct lets you build the object on initialization rather than hard coding the default values like you had...
You could use the default values and create setters, but I like the __construct()
Because the constructor can receive parameters to have the object start with values other than some default values. Without a constructor with parameters, you would have to create a default object, then modify it's fields.
Also note there's always a constructor; it's just a question of whether or not you've created one yourself, or a default one is created for you that doesn't require any arguments.
A constructor in this case simply puts an object into an active state, allocating proper memory.
One may create a Person object with just a name provided as argument, but another constructor may be needed when both a name and age are given as arguments.
In PHP you are limited to 1 unfortunatly, _contruct
You can have multiple constructors built however in a work around way shown here.
There's nothing major difference between both of these.
Both the approaches are fine, and it basically depends upon your use cases.
According to the first approach you are unable to assign values to class members while creating the Class's object whereas in the 2nd approach you have that power, Let me demonstrate this:
class A
{
protected $name = 'John';
protected $age = 20;
}
$obj = new A();
/* Here you get an object with
** $obj->name = 'John'
** $obj->age = 20;
*/
Whereas in approach 2nd you have the power of defining the variables on the go(while defining its Object). Everytime you create an object for Class B you can have different object everytime based on your passed arguments to the class constructor:
class B
{
protected $name;
protected $age;
public function __construct($name = 'John', $age = 20)
{
$this->name = $name;
$this->age = $age;
}
}
$obj = new B("John Doe", 40);
/* Here you get an object with
** $obj->name = 'John Doe'
** $obj->age = 40;
*/
$obj = new B("John Doe");
/* Here you get an object with
** $obj->name = 'John Doe'
** $obj->age = 20;
*/
Classes which have a constructor method call this method on each
newly-created object, so it is suitable for any initialization that
the object may need before it is used
Hope this helps!
What is the difference between a construct method and object properties and when should I use them?
First and foremost, construct() returns an instance of the class you're using, hence why if you ever try return something different inside this method:
public function __construct() { return 'hello, world!'; }
It will not actually work. You're probably asking what this means and why its so important to the question. Well, there are more than just two ways to access data in a property, there are things we call getters and setters.
private $_name;
public function setName($name) { $this->_name = $name; return $this; }
public function getName() { return $this->_name; }
In your use-case, I assume that your data is not constant, it isn't always going to be an age of 25 so you could use multiple ways to approach this. If the data comes from a database, a constructor method would be useful to load the configuration like so:
public $name;
public function __construct($id) {
$user = SomeDriver::GetInstance()->on('Users', '*')->where('user_id = ?', [$id]);
$this->name = $user['username'];
}
Which you can then just access through the instance like $obj->name. However, if you're just setting data through input, you could just use setter/getter or access the properties directly outside the scope;
class User {
public $name = 'Frank';
public function setName($name) { $this->name = $name; return $this; }
public function getName() { return $this->name; }
}
$u = new User;
echo $u->name;
$u->name = 'John';
// or change the property to private and:
$u = new User;
echo $u->getName();
$u->setName('John');
I am following a tutorial and have come across the following code in defining a user class:
class User {
public $id;
public $username;
public $password;
public $first_name;
public $last_name;
public static function instantiate($record) {
$object = new self;
foreach ($record as $attribute => $value){
if ($object->has_attribute($attribute)){
$object->$attribute = $value;
}
}
return $object;
}
private function has_attribute($attribute) {
$object_vars = get_object_vars($this);
return array_key_exists($attribute, $object_vars);
}
}
My question is: What does the "$object->$attribute = $value;" do exactly ?
I am just starting in OOP php and I am really confuse of what that bit of code is downing.
Thanks a lot.
Pretty basic question : it is assigning the value $value to the attribute $attribute of the object $object.
In other words, it is copying the value of the variable $value to the attribute of the object $object.
It's an assignment statement for an attribute of the PHP class. Let's use a less ambiguous example. We will create a small person class that holds a first name and a last name.
class Person
{
//Class attributes
public $fisrtName;
public $lastName;
}
Using the above example, if you wanted to set those attributes, you would do the following:
//Instantiate a new person
$myPerson = new Person();
//Assign values to the person object
$myPerson->firstName = "John";
$myPerson->lastName = "Smith";
Alternately, if you wanted to assign the value myPerson object's firstName field to a different variable, you could do the following:
$personsName = $myPerson->firstName;
All this is doing is internally creating a new instance of it's creating a new instance of it's self for a form of recursion or other functionality,
so calling:
$object->$attribute
is essentially, from what I can see. Will create a new instance then depending on the contents of $attribute return a value or call a method
i was testing the Static Keyword on how exactly does it work and i came across this which i don't understand what is happening.
Consider two Classes ClassNameA & ClassNameB with the following codes.
ClassNameA without Static Keyword
class ClassNameA
{
private $name;
public function __construct($value) {
if($value != '') {
$this->name = $value;
}
$this->getValue();
}
public function getValue() {
echo $this->name;
}
}
ClassNameB with Static Keyword
class ClassNameB
{
private static $name;
public function __construct($value) {
if($value != '') {
self::$name = $value;
}
$this->getValue();
}
public function getValue() {
echo self::$name;
}
}
When i instantiate the object multiple times using ClassNameA
$a = new ClassNameA(12);
echo '<br/>';
$a = new ClassNameA(23);
echo '<br/>';
$a = new ClassNameA(''); //Argument given is Empty here
it outputs the folowing
12
23
And now when i instantiate the object multiple times using ClassNameB
$a = new ClassNameB(12);
echo '<br/>';
$a = new ClassNameB(23);
echo '<br/>';
$a = new ClassNameB(''); //Argument given is Empty here
It outputs the following
12
23
23
Note the extra value 23 it is taking even if the Argument Passed is Empty. Is this a bug? or am i missing something?
This is the nature of static property. The static property is a kind of property of class not the property of object.
When you passed the blank, according to the condition the value of static property will not get updated and last value is still there in the static property.
Since the static property is not bounded with any of the object hence it is available without a need any object.
$a = new ClassNameB(12); //static property is set to 12
echo '<br/>';
$a = new ClassNameB(23); //static property is update to 23
echo '<br/>';
$a = new ClassNameB(''); //static property is not updated here it is still 23
EDIT
You can understand like this:-
if($value != '') {
$this->name = $value; //
}
What the code above is doing it is setting the property value for current object (object which is initializing right now).
So when you wrote
$a = new ClassNameA(12);
What it is doing it is setting the name property to 12 for object a;
$a = new ClassNameA(23);
What it is doing it is setting the name property to 23 for object a;
But when the property is static that is for the whole class not for any object.
so when you wrote
if($value != '') {
self::$name = $value;
}
The code above is setting the static property value. Note that here you wrote self instead of $this which make it use for this class only and not for any of the object.
I tried to explain it better but don't know how it is explaining for you.
A static member is a single instance across the entire application, not once per object. For example
class Example {
static public $var;
static public MyFunction() {
echo "MyFunction\n";
}
}
Example::$var = 123;
echo Example::$var;
Example::MyFunction();
Note how we did not need to create an instance of "Example", essentially its name-spacing the variable to the class. This would be invalid:
$example = new Example();
echo $example->var;
$example->MyFunction();
You can also reference it inside the class as
self::$var
self::MyFunction();
Which makes it safe to rename the class later if you need to. A static function can not access non static member or method though.
is it possible to get the name of the object which calls one of its methods.
scenario:
I have class A. I instantiate 2 objects of that class. If one object calls a method, is it possible to retrieve the name of the object which called it?
EDIT:
class Property() {
public function __call($name, $atts) {
if ($name === 'foo') {
//I want to differ Between Color and Position
}
}
}
$Color = new Property();
$Position = new Property();
$Color->foo();
$Position->foo();
Add a name element to your object:
class ObJA {
$this->name;
function __construct($name){
$this->name = $name;
}
function getName(){ return $this->name; }
}
On object create:
$a = new ObJA('a');
$b = new ObJA('is b');
echo $a->getName(); //`a`
echo $b->getName(); //`is b`
You can always use get_class(), but the name is not going to change simply by creating two or more instances of the object. Neal's solution will work but it doesn't actually change the name of the class, and begs the question: Why do you need it?