3

Working with DateTime in projects again have a problem with duplicating if use array_unique to array which have a elemts of object,(but probles only with DateTime), see code:

class simpleClass
{
    public $dt;

    function __construct($dt)
    {
        $this->dt = $dt;
    }
}

$dateObj = new simpleClass(new DateTime);
$std = new stdClass;
$arr = [$dateObj, $dateObj, $std, $std, $std, $std];

var_dump(array_unique($arr, SORT_REGULAR));

Expected 1 element with dateObj But actually there 2

JB.
  • 40,344
  • 12
  • 79
  • 106
sergio
  • 5,210
  • 7
  • 24
  • 46

2 Answers2

1

Function array_unique() will compare strings, so objects will be casted to strings. Solution to that would be to use __toString() magic method to return full date identifier:

class simpleClass
{
    public $dt;

    function __construct(DateTime $dt) {
        $this->dt = $dt;
    }

    public function __toString() {
        return $this->dt->format('r');
    }

}

$dateObj1 = new simpleClass(new DateTime);
$dateObj2 = new simpleClass(new DateTime);
$dateObj3 = new simpleClass(new DateTime('today'));
$arr = [$dateObj1, $dateObj2, $dateObj3];

print_r(array_unique($arr));

Demo.

Glavić
  • 42,781
  • 13
  • 77
  • 107
  • ehh, but the difference that you create 3 objects, but I trying to find the reason of my problem, I my project, I can not just to create objects such as in your example – sergio Nov 14 '13 at 09:28
  • I find this some kind of bug, and have an issue to find the reasons – sergio Nov 14 '13 at 09:35
  • @sergio: yes, your example is behaving strangelly, it should throw somekind of error, or notice, because if you cast your `$dateObj` or `$std` to string, it will throw `Catchable fatal error: Object of class CLASSNAME could not be converted to string`, but when you use them in function array_unique(), where internal cast to string is performed, no error appears and output is strange... – Glavić Nov 14 '13 at 09:42
  • Hmm, that's why I read a lot of documentation of php but does not find the answer.. – sergio Nov 14 '13 at 09:44
  • 1
    @sergio: nevertheless, `array_unique()` works with strings. `Two elements are considered equal if and only if (string)$elem1===(string)$elem2. In words: when the string representation is the same. The first element will be used.` You are casting objects to strings, that don't have toString magic method, so this is the big error. – Glavić Nov 14 '13 at 09:47
0

I still can't understand. Setting the array with:

$arr = [$dateObj, $dateObj, $std, $std];

returns:

array (size=2)
    0 => 
        object(simpleClass)[1]
            public 'dt' => 
              object(DateTime)[2]
                  public 'date' => string '2013-11-14 14:37:08' (length=19)
                  public 'timezone_type' => int 3
                  public 'timezone' => string 'Europe/Rome' (length=11)
    2 => 
       object(stdClass)[3]

This way, array_unique seems to work...

ilpaijin
  • 3,645
  • 2
  • 23
  • 26
  • Ehh, some strange behaviour – sergio Nov 14 '13 at 13:45
  • Like I said, you cannot work with function `array_unique()` if objects are not convertable to string; results will be unpredictable. [See demo](https://eval.in/67920). – Glavić Nov 14 '13 at 14:05
  • Ok ok, I'm just investigating. It seems to me that also with the magic __toString() it doesn't work. – ilpaijin Nov 14 '13 at 14:44
  • @ilpaijin: can you make a https://eval.in/ example where __toString() doesn't work? It seems hard to believe that it won't work. – Glavić Nov 14 '13 at 21:13
  • 1
    @ilpaijin: remove 2nd parameter `SORT_REGULAR` from `array_unique()` function. [Demo](https://eval.in/68518). – Glavić Nov 15 '13 at 11:27
  • Oh ok, that way too. I found it works with SORT_STRING flag as I saw in the manual "SORT_REGULAR - compare items normally (don't change types)" – ilpaijin Nov 15 '13 at 11:36