2017-10-28 61 views
-3

我們如何通過指定的getter的返回值來排序對象數組?我們有一個對象數組。每個對象都有一個'getCreatedAt'函數,它返回一個DateTime對象。我們需要命令該數組按日期獲取最後一個元素。PHP - 如何使用每個元素上定義的getter來排序對象數組?

+0

這裏有什麼問題? – ccKep

+0

@ccKep更好嗎?謝謝。 – Eloy

+0

我的意思是:你發佈了一個問題,並立即自己回答一個問題? – ccKep

回答

1

解決方案達成了,用於內部對象管理的php特性。現在我們可以通過在我們的實體中實現這個特性來比較其中的一系列對象。這是代碼。

trait ObjectManagement 
{ 
    private function orderObjects(array $objects, string $getter, string $ordering): array 
    { 
     usort(
      $objects, 
      [new ObjectAscDescOrderingByGetter($getter, $ordering), 'order'] 
     ); 

     return $objects; 
    } 

} 


class ObjectAscDescOrderingByGetter 
{ 

    private $getter; 
    private $ordering; 

    public function __construct(string $getter, string $ordering) 
    { 
     if (!in_array($ordering, ['ASC', 'DESC'])) { 
      throw new RuntimeException('Ordering type must be ASC or DESC.'); 
     } 

     $this->getter = $getter; 
     $this->ordering = $ordering; 
    } 

    public function order($objectA, $objectB) 
    { 
     $getter = $this->getter; 

     $comparisonValueA = $objectA->$getter(); 
     $comparisonValueB = $objectB->$getter(); 

     if ($comparisonValueA === $comparisonValueB) { 
      return 0; 
     } 

     if ($this->ordering == 'DESC') { 
      return ($comparisonValueA > $comparisonValueB) ? -1 : 1; 
     } else { 
      return ($comparisonValueA > $comparisonValueB) ? 1 : -1; 
     } 
    } 
} 

我們知道特質不是在某些情況下最好的辦法,但在這種情況下,我們發現它非常有用,因爲這種排序的功能是可以在其他類靜態實現代碼。這是我們現在的使用情況下,實體:

class Car { 

    private $inputDate; 

    public function getInputDate() : DateTime 
    { 
    return $this->inputDate; 
    } 
} 

class CarPark { 
    use ObjectManagement; 
    private $cars; 

    public function getLastCar() : Car { 
    $result = $this->orderObjects($this->cars, 'getInputDate', 'DESC'); 
    return current($result); 
    } 
} 

我們離開這裏的測試也....

class ObjectManagementTestCase extends TestCase 
{ 

    use ObjectManagement; 

    /** 
    * @dataProvider getOrderingCases 
    * @param array $datesToOrder 
    * @param array $datesExpectedOrder 
    * @param string $ordering 
    */ 
    public function testOrdering(array $datesToOrder, array $datesExpectedOrder, string $ordering) 
    { 
     $objectsToOrder = []; 
     foreach ($datesToOrder as $dateToOrder) { 
      $objectsToOrder[] = $this->getOrderableMock($dateToOrder); 
     } 
     $objectsExpectedOrder = []; 
     foreach ($datesExpectedOrder as $expectedDateOrder) { 
      $objectsExpectedOrder[] = $this->getOrderableMock($expectedDateOrder); 
     } 

     $result = $this->orderObjects($objectsToOrder, 'getCreatedAt', $ordering); 
     $this->assertEquals($objectsExpectedOrder, $result); 
    } 

    public function getOrderingCases() 
    { 
     return [ 
      'Must order this in descendant manner.' => [ 
       ['2016-01-01', '2017-01-01', '2017-01-03', '2017-01-05'], 
       ['2017-01-05', '2017-01-03', '2017-01-01', '2016-01-01'], 
       'DESC' 
      ], 
      'Must order this in ascendant manner.' => [ 
       ['2016-01-01', '2017-01-03', '2017-01-01', '2017-01-05'], 
       ['2016-01-01', '2017-01-01', '2017-01-03', '2017-01-05'], 
       'ASC' 
      ], 
     ]; 
    } 

    private function getOrderableMock(string $date) 
    { 
     return new OrderableTestObject($date); 
    } 

    public function testThatInputArrayIsNotModified() 
    { 
     $objects = [ 
      $this->getOrderableMock('2016-01-01'), 
      $this->getOrderableMock('2017-01-03'), 
     ]; 

     $this->orderObjects($objects, 'getCreatedAt', 'DESC'); 

     $this->assertEquals(
      [ 
       $this->getOrderableMock('2016-01-01'), 
       $this->getOrderableMock('2017-01-03'), 
      ], 
      $objects 
     ); 

    } 

    public function testExceptionOnNotRecognizedOrder() 
    { 
     $this->expectException(RuntimeException::class); 
     $this->expectExceptionMessage('Ordering type must be ASC or DESC.'); 
     $this->orderObjects([], 'createdAt', ''); 
    } 
} 


class OrderableTestObject 
{ 
    private $createdAt; 

    public function __construct(string $date) 
    { 
     $this->createdAt = new DateTime($date); 
    } 

    public function getCreatedAt(): DateTime 
    { 
     return $this->createdAt; 
    } 
} 
相關問題