Reputation: 5007
I'm trying to split a holiday in two, given a date in the middle.
$splitdate = new DateTime($_POST['date']);
// Split date = 2020-08-04
$holiday1end = $holiday2start = $splitdate;
$holiday1end->sub(new DateInterval('P1D'));
$holiday2start->add(new DateInterval('P1D'));
echobr("Holiday 1: ".$holiday1end->format("Y-m-d"));
echobr("Then " . $splitdate->format("Y-m-d"));
echobr("Holiday 1: " . $holiday2start->format("Y-m-d");
This is the output I get:
Holiday 1: 2020-08-04
Then 2020-08-04
Holiday 1: 2020-08-04
It doesnt make sense, originally I had the DateInterval as 'P1D' but that didnt work so I tried removing two days, I'm still not getting any changes, or errors either. What am I doing wrong here?
Edit for Clarity: $holiday1end should be one day less than $splitdate, $holiday2start should be one day more than $splitdate, but neither of them are changing.
Upvotes: 0
Views: 431
Reputation: 1752
Adding as new answer instead of rewording / rephrasing old one.
As commented by @Álvaro González on my other answer that objects in many languages behave some what different than what we think when passing objects between different variables.
Quoting from PHP.net
One of the key-points of PHP 5 OOP that is often mentioned is that "objects are passed by references by default". This is not completely true. This section rectifies that general thought using some examples.
A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
Explaination: (what I can understand from this)
If $var1
contains an object and you try to initialize $var2
with $var1
using assignment operator (=
) like $var2 = $var1
the contents of $var1
are copied (passed by value) to $var2
but as per manual, in case of $var1
, $var1
does not contain the object itself as value but a mere object identifier which, in simple words, points to actual object. So in case of above initialization, the object identifier in $var1
is copied (passed by value) to $var2
and as now both variables $var1
, $var2
contain value that points to same object, so it seems that the assignment acted as passed by reference instead of passed by value.
So when you do like this,
$splitdate = new DateTime('2010-12-31');
$holiday1end = $holiday2start = $splitdate;
You are actually coping object identifier of same object to other variables. And as you are sub
tracting and add
ing same number of days, so all these operations are applied to same object. And it seems that the code is not working, however its working properly.
If you do something like bellow, You'll notice that 1 day is added to date (basically 2 days are subtracted and then 3 days are added).
$date = '2010-12-31';
$splitdate = new DateTime($date);
$holiday1end = $holiday2start = $splitdate;
$holiday1end->sub(new DateInterval('P2D'));
$holiday2start->add(new DateInterval('P3D'));
echo "Holiday 1: ".$holiday1end->format("Y-m-d")."\n";
echo "Then " . $splitdate->format("Y-m-d")."\n";
echo "Holiday 2: " . $holiday2start->format("Y-m-d")."\n";
If you separate the DateTime
object instances, you'll get your desired results.
$date = '2010-12-31';
$splitdate = new DateTime($date);
$holiday1end = new DateTime($date);
$holiday2start = new DateTime($date);
$holiday1end->sub(new DateInterval('P2D'));
$holiday2start->add(new DateInterval('P2D'));
echo "Holiday 1: ".$holiday1end->format("Y-m-d")."\n";
echo "Then " . $splitdate->format("Y-m-d")."\n";
echo "Holiday 1: " . $holiday2start->format("Y-m-d")."\n";
If you want to copy the object itself, you can use clone which makes a shallow copy of the object. So using example code in your question with clone
.
$date = '2010-12-31';
$splitdate = new DateTime($date);
// $holiday1end = clone $splitdate;
// $holiday2start = clone $splitdate;
// OR
// $holiday1end = clone $splitdate;
// $holiday2start = clone $holiday1end;
// OR in one line
$holiday2start = clone $holiday1end = clone $splitdate;
$holiday1end->sub(new DateInterval('P2D'));
$holiday2start->add(new DateInterval('P2D'));
echo "Holiday 1: ".$holiday1end->format("Y-m-d")."\n";
echo "Then " . $splitdate->format("Y-m-d")."\n";
echo "Holiday 2: " . $holiday2start->format("Y-m-d")."\n";
You get your desired results(Example).
Upvotes: 0
Reputation: 1752
It seems that when you do like this,
$splitdate = new DateTime('2010-12-31');
$holiday1end = $holiday2start = $splitdate;
The instance of object in $splitdate
is passed as reference to other variables. And as you are sub
tracting and add
ing same number of days, so it seems that the code is not working. However its working properly but due to shared / referenced instance of same object, all effect goes to same object.
However if you do something like bellow, You'll notice that 1 day is added to date (basically 2 days are subtracted and then 3 days are added).
$date = '2010-12-31';
$splitdate = new DateTime($date);
$holiday1end = $holiday2start = $splitdate;
$holiday1end->sub(new DateInterval('P2D'));
$holiday2start->add(new DateInterval('P3D'));
echo "Holiday 1: ".$holiday1end->format("Y-m-d")."\n";
echo "Then " . $splitdate->format("Y-m-d")."\n";
echo "Holiday 2: " . $holiday2start->format("Y-m-d")."\n";
If you separate the DateTime
object instances, you'll get your desired results.
$date = '2010-12-31';
$splitdate = new DateTime($date);
$holiday1end = new DateTime($date);
$holiday2start = new DateTime($date);
$holiday1end->sub(new DateInterval('P2D'));
$holiday2start->add(new DateInterval('P2D'));
echo "Holiday 1: ".$holiday1end->format("Y-m-d")."\n";
echo "Then " . $splitdate->format("Y-m-d")."\n";
echo "Holiday 1: " . $holiday2start->format("Y-m-d")."\n";
Upvotes: 1