Doubt about class Abstract and method __Construct?

Asked

Viewed 54 times

1

I have the following class:

abstract class Weeks
{

  protected $year;
  protected $this_week;
  protected $last_week;

  /**
  * @param $date deverá ser no formato new DateTime().
  **/
  public function __construct($date)
  {
    $this->year = $date->format('Y');
    $this->this_week = $date->format('W');
    $this->last_week = ($date->sub(new DateInterval('P1W')))->format('W');
  }
}

There I extend it within other classes for example:

class Training_Load_Week extends Weeks
{

      private $trainingLoadThisWeek;

      /**
      * @param $training_load é um array multidimensional contendo todos os treinos separados por [ano][numero_da_semana](treinos)
      **/
      public function setTrainingLoadThisWeek($training_load)
      {
        $this->trainingLoadThisWeek = array_sum( $training_load[$this->year][$this->this_week] );
      }

      public function getTrainingLoadThisWeek()
      {
        return $this->trainingLoadThisWeek;
      }
}

$training_load_week = new Training_Load_Week($today);
$training_load_week->setTrainingLoadThisWeek($arr_tl);

And this:

class Training_Load_Last_Week extends Weeks
{

      private $trainingLoadLastWeek;

      /**
      * @param $training_load é um array multidimensional contendo todos os treinos separados por [ano][numero_da_semana](treinos)
      **/
      public function setTrainingLoadLastWeek($training_load)
      {
        $this->trainingLoadLastWeek = array_sum( $training_load[$this->year][$this->last_week] );
      }

      public function getTrainingLoadLastWeek()
      {
        return $this->trainingLoadLastWeek;
      }
}

$training_load_last_week = new Training_Load_Last_Week($today);
$training_load_last_week->setTrainingLoadLastWeek($arr_tl);

What is happening is the following, the date is not always starting on the date given in the variable $today

It continues from where it left off in the use of the first class, for example, it was supposed to be week 34 to $this->week and week 33 to $this->last_week

But when I call the second class, it does not use those same values, it continues from where it left off in the previous class uses, that is, returns the values $this->week like 33 and $this->last_week like 32, but it should be 34 and 33 again.

I don’t understand why.

  • because you need to call the abstract class builder !!! and be explicit in that statement.

  • There is already an explanation on the subject: https://answall.com/questions/45297/posso-declarar-um-construct-construct-nas-classes-filhas-quando-a-classe-m%C3%A3e-%C3%A9-abstract-e

1 answer

3


The problem is occurring with the argument $date constructor public function __construct($date). Even if the php default for passing arguments is the passage by value for primitive types, for complex types like the object DateTime this passage of arguments is made by reference implying that any change in the argument $date shall be effectively carried out by reference to its object $today = new DateTime();.

To make the finding that it is a problem with an unintended modification in the referenced object I changed the class constructor Week in order to display the input and output values of $date:

abstract class Weeks
{

  // Tornei os membros $year, $this_week e $last_week públicos somente para facilitar meus testes
  public $year;
  public $this_week;
  public $last_week;

  /**
  * @param $date deverá ser no formato new DateTime().
  **/
  public function __construct($date)
  {
    // Aqui mede o valor de entrada do argumento $date
    print_r("valor de entrada = ". $date->format('W'). "\n");

    $this->year = $date->format('Y');
    $this->this_week = $date->format('W');
    $this->last_week = ($date->sub(new DateInterval('P1W')))->format('W');

    // Aqui mede o valor de saída do argumento $date após o código
    print_r("valor de saída = ". $date->format('W'). "\n");
  }
}

So I ran four tests:

echo "$training_load_week";
$training_load_week = new Training_Load_Week($today);
echo "$training_load_week1";
$training_load_week1 = new Training_Load_Week($today);
echo "$training_load_last_week";
$training_load_last_week = new Training_Load_Last_Week($today);
echo "$training_load_last_week1";
$training_load_last_week1 = new Training_Load_Last_Week($today);

And result was:

$training_load_week
valor de entrada = 34
valor de saída = 33

$training_load_week1
valor de entrada = 33
valor de saída = 32

$training_load_last_week
valor de entrada = 32
valor de saída = 31

$training_load_last_week1
valor de entrada = 31
valor de saída = 30

Ok this confirms the unwanted modification in the reference. Now the next step is to identify what is causing the modification.

Analyzing the documentation of the functions used in the constructor I found the cause on the line...

$this->last_week = ($date->sub(new DateInterval('P1W')))->format('W');

...more precisely in the method $date->sub. This method not only returns the modified date but effectively modifies the object that evokes it in the case the object $today which is referenced by $date within the constructor. To repair this code is simple just make a clone of the argument $date.

abstract class Weeks
{
  // Tornei os membros $year, $this_week e $last_week públicos somente para facilitar meus testes
  public $year;
  public $this_week;
  public $last_week;

  /**
  * @param $date deverá ser no formato new DateTime().
  **/
  public function __construct($date)
  {
    // Está qui o reparo do código
    $date = clone $date;

    print_r("valor de entrada = ". $date->format('W'). "\n");

    $this->year = $date->format('Y');
    $this->this_week = $date->format('W');
    $this->last_week = ($date->sub(new DateInterval('P1W')))->format('W');

    print_r("valor de saída = ". $date->format('W'). "\n");
  }
}

I repeated the same tests and the result was:

$training_load_week
valor de entrada = 34
valor de saída = 33

$training_load_week1
valor de entrada = 34
valor de saída = 33

$training_load_last_week
valor de entrada = 34
valor de saída = 33

$training_load_last_week1
valor de entrada = 34
valor de saída = 33
  • 1

    Thank you so much for all the explanation. I would never find that out, I am apprentice in the subject yet, php study for personal goals.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.