Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 20 days ago.
Improve this question
I consider a slug property not being a part of my domain model. It's just a nice convenience for the view layer.
But still: I don't want to calculate it each time I retrieve it to the view.
So I decide to only define a private property with a getter on entities which eventually will be retrieved via an URL - through a Sluggable contract. The constructor doesn't touch it all. I delegate the slug's creation to an Infrastructure Service. The ORM deals with entities using reflections, so my solution kind of looks like how Doctrine would touch those.
I register the event lifecycle listener as a Symfony service.
<?php
namespace App\Common\Domain\Model;
interface Sluggable
{
public function slug();
}
<?php
namespace IMS\Registry\Domain\Model\Manufacturer;
use App\Common\Domain\Model\Sluggable;
class Manufacturer implements Sluggable
{
private ManufacturerId $id;
private ManufacturerName $name;
private string $slug;
public function __construct(ManufacturerId $anId, ManufacturerName $aName)
{
$this->id = $anId;
$this->name = $aName;
}
public function name(): ManufacturerName
{
return $this->name;
}
public function slug(): string
{
return $this->slug;
}
// other methods
}
<?php
namespace App\Common\Infrastructure\Domain\Model;
use App\Common\Domain\Model\Sluggable;
use Cocur\Slugify\SlugifyInterface;
use Doctrine\Persistence\Event\LifecycleEventArgs;
class NameSlugger
{
public function __construct(private readonly SlugifyInterface $slugger)
{
}
public function prePersist(LifecycleEventArgs $args): void
{
$this->preSlugged($args);
}
public function preUpdate(LifecycleEventArgs $args): void
{
$this->preSlugged($args);
}
private function preSlugged(LifecycleEventArgs $args): void
{
$entity = $args->getObject();
if (!$entity instanceof Sluggable) {
return;
}
$reflection = $args->getObjectManager()->getClassMetadata($entity::class)->getReflectionClass();
if (!$reflection->hasProperty('slug')) {
throw new \ReflectionException();
}
$reflectionProperty = $reflection->getProperty('slug');
if (!$reflectionProperty->hasType()) {
throw new \ReflectionException();
}
$reflectionPropertyType = $reflectionProperty->getType()->getName();
if ('string' !== $reflectionPropertyType) {
throw new \ReflectionException();
}
$reflectionProperty->setValue(
$entity,
// ManufacturerName VO has a __toString method
$this->slugger->slugify($entity->name())
);
}
}
My question is: is my reasoning valid in your opinion? From a DDD perspective. What different approach would you incorporate so it fits the DDD concept of a project?
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.
}
}
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I have a weird problem in PHP. I have two classes, one extending another. The problem is that i when I try to access a variable in the parent class (via a getVar() method), it returns undefined, even though it had been already defined in the parent's constructor.
class HttpClient
{
private $errorList;
public function __construct()
{
$errorList = [];
}
public function getHttpErrorList() { return $errorList; }
//...
}
class Twitter extends HttpClient
{
public function __construct()
{
parent::__construct();
//..
}
public function getMessages()
{
//...
var_dump($this->getHttpErrorList()); //returns undefined variable!
}
What is the cause of this problem and how do I solve it?
Defining $errorList=[] inside your constructor is defining a local variable to the constructor. I.e. variable $errorList is undefined in method getHttpErrorList() - if you want access to $errorList at the object level, you need to change it to $this->errorList inside your constructor and in method getHttpErrorList().
<?php
class HttpClient
{
private $errorList;
public function __construct()
{
$this->errorList = []; // change to $this->errorList
}
public function getHttpErrorList() { return $this->errorList; } // change to $this->errorList
//...
}
class Twitter extends HttpClient
{
public function __construct()
{
parent::__construct();
//..
}
public function getMessages()
{
//...
var_dump($this->getHttpErrorList()); //outputs array(0) {}
}
}
$twit = new Twitter();
$twit->getMessages(); // output: array(0) { }
There are two classes:
class Product {
public id;
public name;
}
class OrderCustomer
{
public $DeliveryDate;
public $PhotoBefore = 0;
public Product[] products;
}
So, I attempt to specify property products in class OrderCustomer as Product type. It should be array of products.
How to do that in php?
As mentioned in the comments, PHP is not a strongly typed language and what you are looking for is not possible, at least not in the same way it is in languages like C# and Java. You can get close to that functionality by enforcing what is added to the $products class member by making adding values to it limited to a setter class method that only accepts variables whose type is Product.
To get the type hint you would need to use a Doc Prop explicitly stating that that variable is intended to hold and array products.
class Product {
public $id;
public $name;
}
class OrderCustomer
{
public $DeliveryDate;
public $PhotoBefore = 0;
/** #var Product[] */
public $products = [];
public function addToProductArray(Product $product)
{
$this->products[] = $product;
}
}
Because $products is now protected make sure you also make a getter for getting its value from outside of the class (i.e. by the calling code) if you intend for it to be accessed that way.
given a class:
class Cart
{
private $items;
public function add (Product $item)
{
$this->items[] = $item;
}
public function clear()
{
$this->items = array();
}
}
this is just cool. But for testing, lets make a possibility to change the items:
class Cart
{
private $items;
public function add (Product $item)
{
$this->items[] = $item;
}
public function clear()
{
$this->items = array();
}
public function setItems ($items)
{
$this->items = $items;
}
public function getItems()
{
return $this->items;
}
}
but I think its not a good solution as the getItems, setItems isnt really related to the class itself. Of course, I can write that:
class Cart extends DI
{
protected $items;
public function add (Product $item)
{
$this->items[] = $item;
}
public function clear()
{
$this->items = array();
}
}
class DI
{
public function setItems ($items)
{
$this->items = $items;
}
public function getItems()
{
return $this->items;
}
}
but what if I have $items and $discounts too? There is no multiple inheritance
Side note: Having a superclass with functions using the protected variables of a subclass is generally bad practice, since inheritance should only go one way, and that way is down, never up. What if someone creates a DI class and then calls a setItems or getItems function? Trouble! Do NOT practice the last example of code.
My answer:
The Setters/Getters ARE related because Cart has the single responsibility of providing functionality towards $items. The way I see it, you do not violate SRP using DI, since all you're doing is defining the dependency outside the class before sending it in, giving $item no reason to change and sharing no responsibility. Your second code example is the correct solution in this case.
Your third example violates SRP since the Cart class shares responsibility of $items with the DI class.
Some links:
See this article for more information about Dependency Injection:
http://tutorials.jenkov.com/dependency-injection/dependency-injection-benefits.html
SRP: https://en.wikipedia.org/wiki/Single_responsibility_principle