D
D
Danbka2018-07-20 11:49:51
PHP
Danbka, 2018-07-20 11:49:51

How to create an object with a lot of properties?

Hello.
To illustrate the issue, I will give a spherical example in a vacuum.
There is a class whose task is to write product data to a file. The write() method takes an object of the Product class as a parameter and makes sure that the object has the required properties.

Class ProductWriter
{
  public function write(Product $product)
  {
    // write to file
  }
}

Product has many properties (about 20): name, description, price, size, color, shape, etc. etc. Moreover, some of the properties are mandatory, some are optional.
What is the optimal way to write the Product class?
My options are:
1) The Product class constructor accepts an associative array of parameters. The constructor checks for the presence of required fields. It seems to me that this method is not the best: the client code does not know which keys should be present in the input array.
2) Create a bunch of properties and getters/setters for them:
Class Product
{
  private $name;
  private $price;
  // ...

  public function setName() {}
  public function setPrice() {}
  // ...

  public function getName() {}
  public function getPrice() {}
  // ...
}

But then again - how does the client code know that after creating the object, it is necessary to call some setters?
$product = new Product();
$product->setName('name');
$product->setPrice('0.0');

3) Well, the most trash - a constructor with 20 parameters:
Class Product
{
  function __construct($name, $price, $color, $size, ....)
  {

  }
}

So, of course, the client code will specify all required fields exactly. But you shouldn’t do that, it’s written in the books))
If we talk about options No. 1 and No. 2: in fact, no one except me will use this class. And I know exactly what needs to be filled out about the product. But I would like to solve the problem "beautifully".
PS. I foresee comments along the lines of: why one generic product class? Create subclasses with only the properties you need and you'll be happy.
To this I will answer that my example with the product is conditional. In my case, it’s really an entity with a bunch of properties, from which nothing can be inherited and broken into simpler entities.

Answer the question

In order to leave comments, you need to log in

5 answer(s)
M
Maxim Fedorov, 2018-07-20
@Danbka

Required parameters should be set in the class constructor - this will ensure that they are mandatory, optional using getters and setters. In addition, it is worth reconsidering whether all required fields are really required - or some are still not + if possible, parameters should be packed into value objects

S
Sergey Sokolov, 2018-07-20
@sergiks

Accept an associative array. Add missing properties with default values ​​or throw an exception when a required property is missing.

A
ApeCoder, 2018-07-20
@ApeCoder

See if there is a relationship between properties. Perhaps there are groups of related properties that can be separated into separate classes.
Mandatory properties - constructor parameters, the rest properties.
See also creation patterns, such as factory method and builder.

Z
Zanak, 2018-07-30
@Zanak

I would break the task into 2 parts: creating an object and using it.
Creating an object:
- In addition to mandatory, there can be conditionally mandatory (this is the case when setting one parameter makes a certain number of parameters mandatory) and optional.
- When all parameters are required, we write the constructor.
- It may make sense to wrap the initialization of conditionally required parameters with an auxiliary class, which can be made available only in the context of the main class, and include a check of the passed parameters in its implementation.
- The construction of classes with conditionally required and optional parameters, in addition to direct parsing of parameters, can be implemented using factories that will contain a smaller number of parameters and set the omitted ones to the correct default values.
- Instead of a factory, you can hide your class behind a facade with a simpler interface.
- Also, you can create several methods for constructing an object, and implement the constructor as a dispatcher that will call the one you need, depending on the parameters passed.
Using Objects:
- For conditionally required parameters, it is unavoidable to create methods that accept the entire tuple of related parameters. This is instead of separate setters for each property.
- In addition to set / get access methods, you can use direct access to properties, all or some, especially if there is a mutual dependence of parameters, and creating a full-fledged validator for the entire set of constructor parameters cannot be avoided.
If the answer is the most general, then I would do something like this.

N
Northern Lights, 2019-06-29
@php666

$product = new Product();
$product->setData($data); // $data - массив со значениями. 
// Берем ключи каждого элемента $data, приводим к camelCase, пытаемся найти такой set-метод 
// в объекте product и вызвать его с относящимся к ключу значением
print_r($product->getModelErrors()); // проверяем, насколько корректно заполнен продукт

how getModelErrors works: the product class has a certain map of valid model properties. Whether the property is required or not. If not, what is the default value. You can hang validation on each of the described properties. Those. create a system of validators and apply from 0 to an infinite number of different validators to each property. This is how I do it in my framework .

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question