PHP / Doctrine - 在for()循环外部使用flush()保存日期时间

I have a small issue with recording three entities with a date-time property in a loop.

Here is the code I used :

$today = new DateTime();
$frequency = 3;

for($i=1;$i<=3;$i++) {
    $interval = DateInterval::createFromDateString("+".($i * $frequency)." days");
    $reminder = new Reminder();
    $reminder->setNumber($i);            
    $reminder->setScheduledAt($today->add($interval));            
    $this->em->persist($reminder);            
}
$this->em->flush();

So, with flush() statement outside the loop, there are 3 reminders recorded but with the same 9 days difference in the date-time property equal to the last date-time calculated.

However, with the doctrine flush() inside the loop:

$today = new DateTime();
$frequency = 3;

for($i=1;$i<=3;$i++) {
    $interval = DateInterval::createFromDateString("+".($i * $frequency)." days");
    $reminder = new Reminder();
    $reminder->setNumber($i);            
    $reminder->setScheduledAt($today->add($interval));            
    $this->em->persist($reminder); 
    $this->em->flush();
}

All three date are recorded right (meaning with a datediff equal to 3,6 and 9 days from the todays date) It seems to me that the flush() should stay outside the loop... what am I missing here ?

here is my entity :

/**
 * @ORM\Column(type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @ORM\Column(type="integer",length=1)
 */
private $number;

/**
 * @ORM\Column(type="datetime",nullable=true)
 */
private $scheduledAt;

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\WorkFlowStep" , fetch="EAGER")
 * @ORM\JoinColumn(referencedColumnName="id")
 */
private $step ;

Thank you for your time.

This is because you are modifying DateTime object in loop. When flush is outside the loop scheduleAt attribute is set to the same object with 9 days reminder. You should create three different DateTime objects e.g with cloning:

$today->add($interval);
$scheduledAt = clone $today;
$reminder->setScheduledAt($scheduleAt);

// flush outside the loop

In this case entities have scheduledAt properties set with 3 different dates.

When you have flush inside the loop (not recommended) you are saving to DB cureent DateTime object state with 3 days intervals.

Note:

The simplest solution would be to use \DateTimeImmutable. In such case whenever you call: modify method you would receive new \DateTimeImmutable object - cloning is not needed and you can call: modify in loop.