Use of __construct or setVar() [duplicate] - php

I have been searching for this online, but I can't seem to find something that is clear enough for me to understand. I have seen "similiar" questions on here about this in Java.
class animal{
private $name;
// traditional setters and getters
public function setName($name){
$this->name = $name;
}
public function getName(){
return $this->name;
}
// animal constructors
function __construct(){
// some code here
}
// vs
function __construct($name){
$this->name = $name;
echo $this->name;
}
}
$dog = new animal();
$dog->setName("spot");
echo $dog->getName();
// vs
$dog = new animal("spot");
Should I declare and access my private fields through setters and getters or through the constructor?
Which one is the best practice?
I understand the purpose of a constructor(maybe not), but what is the point of having a constructor if I can declare and access my private fields through setters and getters?
Please note...this is my first time using OOP with web development and PHP, and I'm trying to learn by getting my hands "dirty" by writing some code in order for me to understand certain things in OOP. Please keep it simple.

It is more a matter of semantics than best practice per say.
In your example, your buisness logic may determine that an animal always needs a name.
So it makes sense to construct the object with a name. If you do not want to allow
an animal's name to be changed, then you don't write a setter.
i.e.
class Animal
{
private $name;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
You may have other properties that an animal doesn't have to have, like an owner
that you only write a getter/setter for i.e.
class Animal
{
private $name;
private $owner;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function setOwner($owner)
{
$this->owner = $owner
}
}
But if you find that you are always creating an animal with an owner at the same time
you may want to put that in the contructor signature for convenience
class Animal
{
private $name;
private $owner;
public function __construct($name, $owner = null)
{
$this->name = $name;
$this->owner = $owner;
}
public function getName()
{
return $this->name;
}
public function setOwner(Owner $owner)
{
$this->owner = $owner
}
public function getOwner()
{
return $this->owner;
}
}
If the owner is another class in your application, you can type hint that your constructor
needs an owner of a specific type (class). All of this is used to make it easier for you, or another developer to understand some of the requirements/logic behind your code - as well as potentially catching a bug here or there
class Owner
{
private $name;
public function __construct($name)
{
$this->name = $name;
}
}
class Animal
{
private $name;
private $owner;
public function __construct($name, Owner $owner = null)
{
$this->name = $name;
$this->owner = $owner;
}
public function getName()
{
return $this->name;
}
public function setOwner(Owner $owner)
{
$this->owner = $owner
}
public function getOwner()
{
return $this->owner;
}
}
// Create a new owner!
$dave = new Owner('Farmer Dave');
// a standard php empty object
$otherObj = new \stdClass();
// Create a new animal
$daisy = new Animal('Daisy');
// Farmer dave owns Daisy
$daisy->setOwner($dave);
// Throws an error, because this isn't an instance of Owner
$daisy->setOwner($otherObj);
// Set up Maude, with Dave as the owner, a bit less code than before!
$maude = new Animal('Maude', $dave);

Should I declare and access my private fields through setters and getters or through the constructor?
In situations like this, I ask myself:
Why should I create a method just to hold a one line function? (+Constructor)
How painful is it going to be to refactor two, three, four, five or more getters/setters vs one constructor?(+Constructor)
How hard is it going to be to document two, three, four, five or more getters/setters vs one constructor?(+Constructor)
Is there going to be a default value which will be documented? (+Constructor)
Do I like documentation and expect people to read? (+Constructor)
Will the initial value be undefined?(+Setter)
Is there a set of equivalent forms (shorthand, international, nicknames) which will all be acceptable as syntatically correct for required arguments? (+Setter)
Is there a set of optional arguments with default values? (+Setter)
Is there a common need to stringify and parse the initial value? (+Setter)
Do I dislike documentation and expect people to experiment? (+Setter)
Which one is the best practice?
The Date object seems to be the most complex class in most languages, so its PHP implementation would be a good reference for best practices.
What is the point of having a constructor if I can declare and access my private fields through setters and getters?
A constructor is implicitly invoked upon object instantiation in order to encapsulate the default state of the resulting data structure of its type.
References
DateTime::__construct
date_create
The DateTime class
date_default_timezone_get
date_default_timezone_set
Changes in PHP datetime support
PHP OOP: Accessor and Destructor Methods
Concurrency, part 4: Comparing promises frameworks in different languages – SLaks.Blog
CDD: Context-Driven Development

Depends. Usually one say: If it's a required dependency, use the constructor, if it's optional, use getter/setter.
There is no preference for, or against one of them.
The constructor contains code, that is executed right after the object is created and it should leave the object in a stable and useable state. Thats the idea behind the constructor and it doesn't work in any case, but it should give you an idea, what should go into it.
Note, that you can even implement both constructor arguments and setters for the same property, for example if you want to allow to replace property later.
$bingo = new Dog;
echo $bingo->getName(); // DogHasNoNameException <-- maybe better as constructor argument?
$bingo = new Dog('Bingo');
echo $bingo->getName(); // "Bingo"
$spike = new Dog; // Missing argument
$bingo->setName('Spike'); // Or maybe "rename()" ;)
echo bingo->getName(); // "Spike"

Should I declare and access my private fields through setters and
getters or through the constructor? Which one is the best practice?
Both. It depends on your needs. If need a value in certain fields you add a param to the
__construct()-Method to do so. Or you can also add an optional Param to __construct to give the user the option to set the attribute
I understand the purpose of a constructor(maybe not), but what is the
point of having a constructor if I can declare and access my private
fields through setters and getters?
The contructor should initialize your attributes which need to be initialized.

In my opinion, it is more correct to write setter's & getter's, since then, the number of properties will only grow. And the __construct can then take an array of properties of the names of the keys (property => value), and set them to properties.

1 > That's your chose : if dependency is required, good practise use the constructor, else, use getter.
2 > for the best practise is the first,
Actually, you have a name, for your animal, but if you add a type and sex? and you want to call type, sexe or name separatly, first method is more better than the second.
class animal{
private $name, $type, $sex;
// traditional setters and getters
public function setName($name){
$this->name = $name;
}
public function setSex($sex){
$this->sex = $sex;
}
public function setType($type){
$this->type = $type;
}
public function getName(){
return $this->name;
}
public function getSex(){
return $this->sex;
}
public function getType(){
return $this->type;
}
// animal constructors
function __construct(){
// some code here
}
}
$dog = new animal();
$dog->setName("spot");
$dog->setSexe("male");
$dog->setType("dog");
echo $dog->getName().' is a '.$dog->getType().'('.dog->getSex().')';
3 > that depends first question... BUt Globaly we are always one dependency required, for sample:
class animal{
private $name, $type, $sex;
// traditional setters and getters
public function setName($name){
$this->name = $name;
}
public function setSex($sex){
$this->sex = $sex;
}
private function setType($type){
// if type is string ( cat, dog, lion ) and you want
// to linked string in an id in your database (1, 2, 3...).
// you want to call your database connection ( declared in you constructor)
// and search type id here.
$this->type = $type;
}
public function getName(){
return $this->name;
}
public function getSex(){
return $this->sex;
}
public function getType(){
return $this->type;
}
// animal constructors
public function __construct($type){
// for sample you want to open your database here
this->setType($type);
}
public function __destruct(){
// and you want to close your connection here.
}
}

Related

Unserialized object can't be passed from origin?

So I have a complex object which I wish to cache after creation as it is expensive to initialize. I'm able to reconstitute an instance within the class defining file but I need to be able to return the reconstituted instance in place of a new MyClass if my scheme is going to be of any use. (Don't I?)
Here's what I've done so far:
class PayPeriodService
{
public $type; // weekly,bi-weekly, semi-monthly, monthlly
public $payday_first;
public $close_first;
public $hours_start;
public $hours_end;
public $length; // in days
public $periods; // array of all periods this year
public $dayInterval;
public $oneWeekInterval;
public $twoWeekInterval;
public $semiFirstInterval;
public $monthInterval;
public $initialYear;
public $today; // date object
public function __construct()
{
if( Redis::exists('pay-period-instance')) {
Log:info( 'Fetching Pay-Period from cache.');
$instance = json_decode(Redis::get('pay-period-instance'));
// var_dump( $instance );
// exit();
return $instance;
}
return $this->init();
}
public function init()
{
Log::info('Reconstituting Pay-Period from primitive definition.');
$ppdef = PayPeriod::all()->last();
// etc etc etc, setting up all the properties, loading arrays etc
// finally I cache the object
Redis::set('pay-period-instance', json_encode($this));
return $this;
}
}
So when I instantiate this class, with $ppsvc = new PayPeriodService; in another class, the $instance variable in the PayPeriodService file is valid and fully reconsituted, fully functional. But the returned instance in $ppsvc is a mindless zombie shell of what it ought to be: no instance data, no methods.
What is the magic I need to invoke to get the restored object to travel abroad as it needs must do? I have explored the Serializable interface, and tried with un/serialize in place of the json_encode/decode with no significant change to my problem.
The problem is that __construct() method does NOT return anything. What you want is a singleton (AFAICU).
Look at this example:
class A {}
class B {
public function __construct(){return new A;}
}
$b = new B;
print_r($b); // B
So has you see even having the constructor returning a different class, that is not going to happen. There are several ways to accomplish this, so you can take a look on the web.
A simple example:
class PayPeriodService {
/**
* #var self
*/
static private $instance;
// private removes the possibility to make a new instance
private function __construct()
{
// object construction logic here
}
/**
* #return PayPeriodService
*/
static public function getInstance()
{
if(!self::$instance)
{
self::$instance = new static;
}
return self::$instance;
}
}
$ppsv = PayPeriodService::getInstance(); // will return what you intend
Unless the object is constantly mutating on Redis, this will do the trick. But you can easily adapt if needed

PHP Class attribute call constructor

I wrote the following example class:
class Test {
public $baseSymbol;
public $counterSymbol;
public function __construct($baseSymbol,$counterSymbol) {
$this->baseSymbol = $baseSymbol;
$this->counterSymbol = $counterSymbol;
}
public static $var = new Test("CV", "SWR");
}
As you may noticed, I want that the attribute $var of the class Test become a Object of type Test. I did the same thing easily in Java, as a public static variable, but in PHP it's not working...Is there any alternative for what I'm trying to do?
Because you cant set complex types within the definition of the class variables, the only way I can perceive doing this in PHP is to use the magic of procedural code ( Joke ). Now It's important to note that within the file the class exists in you can certainly do something like this.
class Test {
public $baseSymbol;
public $counterSymbol;
protected static $var;
public function __construct($baseSymbol,$counterSymbol) {
$this->baseSymbol = $baseSymbol;
$this->counterSymbol = $counterSymbol;
}
public static setVar(Test $var ){
self::$var = $var;
}
}
Test::setVar( new Test() );
This is pretty standard fare, but as mentioned above by placing the setting code within the class, when the file is loaded the setting is done immediately and pre-loads the class instance before anything else can be done.
This is simply a consequence of not being pre-compiled. When the class is loaded there is no guarantee that a complex object that is required is present, and because of that PHP plays it safe and restricts this ability.
I did change the variable to be protected to keep it encapsulated, this of course is optional. I also added type casting which will insure that only an object or descendant object of Test is used as the input.
Probably not the most favorable solution but one that will work. One last thing you could do just to make sure if you really want to keep it from being changed is to change the setter like this.
public static setVar(){
if( !self::$var ){
self::$var = new Test();
}
}
This way you just call the method with Test::setVar() and once it's got a value it always returns not false, so it will not be changed latter.
One last note, if you truly want a copy of the class itself, this is the Test class with a static instance of itself ( like a singleton ) then do this instead of using the name
public static setVar(){
if( !self::$var ){
self::$var = new self;
}
}
Now to wrap that into a singleton, you can do the class like this.
final class Test {
public $baseSymbol;
public $counterSymbol;
protected static $var;
//no constuction
private function __construct($baseSymbol,$counterSymbol) {
$this->baseSymbol = $baseSymbol;
$this->counterSymbol = $counterSymbol;
}
//no cloning
private function __clone(){}
public static getInstance(){
if( !self::$var ){
self::$var = new self('%', '#');
}
return self::$var
}
}
$Test = Test::getInstance();
Here I go rambling, now ponder saving the instance in an array with a key. Then you can have a Multiton ( is that a thing? );
public static getInstance($type, $baseSymbol,$counterSymbol){
if( !isset(self::$var[$type] )){
self::$var[$type] = new self($baseSymbol, $counterSymbol);
}
return self::$var[$type];
}
It makes a great database class, just saying.
You could access $var via a getter and initialize it there on demand:
private static $var;
public static function getVar()
{
if (null === self::$var) {
self::$var = new Whatever();
}
return self::$var;
}

PHP Class, considered bad practice? setters and getters

quick question:
Is it considered bad practice to set something in a Construct function like so:
Class whatever {
$var = "";
public function __construct($var){
$this->var = $var;
}
//And then return it in another function like
public function getVar(){
return $this->var;
}
}
Yes, it is bad practice since you not declare $var and not are using a setter method. The meaning with getter and setter methods completely vanyshes when you not declare the variable, and not declare it private or protected. Then you could just go with $class->var=something.
Class whatever {
private $var;
public function __construct($var){
$this->setVar($var);
}
public function setVar($var){
$this->var = $var;
}
public function getVar(){
return $this->var;
}
}
no it is a good practice .
suppose you have 20 fields , and you must fill them to use class correctly .
good practice is to initialize them in the construction . if you use setter you must call 20 methods .
You have good answers, but I'll give you a rundown on some more info
what is the constructor for?
Use a constructor in your classes if your class instances need initialization
a getter for variables set in the constructor could be useful as a way to find out how the instance was initialized
setters
You need these when you need to modify the behaviour of your instance, or when you want to load data into it
getters
The only way to retrieve the contents of the instance (public properties are not encouraged due to a plethora of reasons)
My example
Feel free to do what you wish with this, it's only an example and it's obviously not doing anything. If you want to ask anything about this, please do
<?php
class AnExampleClass {
// this is convenient sometimes but I don't recommend it
public $public = '';
protected $protected;
private $private;
public function __construct($private, $protected){
$this->private = $private;
$this->setProtected($protected);
}
public function getPrivate(){
return $this->private;
}
public function getProtected() {
return $this->protected;
}
public function setProtected($protected) {
// only allow boolean
$this->protected = (bool)$protected;
}
public function __get($name) {
// read the manual on this magic
}
public function __set($name, $value) {
// read the manual on this magic
}
}

PHP Classes load() method good/bad practice?

Just wondering if you could shed some light on best practices?
Would having a load method in a Class be the correct/best way?
Class Test extends Foo{
public $id;
public $name;
public function __construct()
{
parent::__construct();
}
public function load($id, $name)
{
$this->id = $id;
$this->name = $name;
}
}
Or would it be concidered better practice to just have the load method logic in the constructor?
Class Test extends Foo{
public $id;
public $name;
public function __construct($id, $name)
{
parent::__construct();
$this->id = $id;
$this->name = $name;
}
}
The 2nd option seems to be more logical to me as it's one less method and it's called automatically etc, however, I've seen the 1st option more often. Is there a reason for this? Any help would be appreciated!
The second option is best. A constructor is meant to prepare the object for use. It is the perfect place to initialize properties etc. Unless you have a good reason for using load() instead of the constructor, go with the second example.
The first option uses slightly more abstraction, I suppose.
I can see a situation where you might need to copy the code and separating the variable assignments into a load() or init() function might make your code a litter easier to update for the new purpose.
An advantage of the 1st option is that you don't require the developer to supply the information straight away. Although it is more error prone since one might forget about calling the load function. If all other functions require $id and $name to be set it's best to require the arguments when creating a new object.
On the other hand not having the load function prevents you from reloading the object with new values later on in the code.
You can combine the two by calling the load function from the constructor:
Class Test extends Foo{
public $id;
public $name;
public function __construct( $id, $name )
{
parent::__construct();
$this->load( $id, $name );
}
public function load($id, $name)
{
$this->id = $id;
$this->name = $name;
}
}
OR if you don't require the values to be set on creation you can use PHPs funky function overloading stuff:
Class Test extends Foo{
public $id;
public $name;
public function __construct()
{
parent::__construct();
if( func_num_args() === 2 ){
call_user_func_array(array($this, 'load'), func_get_args() );
}
}
public function load($id, $name)
{
$this->id = $id;
$this->name = $name;
}
}
You could extend load() per particular member.
Making each property protected or private and providing a set/get function for one of them.
That's an acceptable way and sometimes is better than overloading your constructor with dependencies and logic.
Try this and see if it helps you:
Class Test extends Foo{
protected $id;
protected $name;
public function __construct()
{
parent::__construct();
}
public function setId($id) {
$this->id = $id;
}
public function setName($name) {
$this->name = $name;
}
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
}
It's called getters and setters and it's a more clean and robust approach.
Besides, as mentioned in other answers - It provides better re-usability, ability to have your object clean of data with null values, but that's all dependent on what is the intent of your class!

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);

Categories