* 目录结构
* 基类 Pet.php
<?php
/**
* Created by PhpStorm.
* User: Mch
* Date: 9/24/18
* Time: 3:30 PM
*/
namespace stack\dogcat;
class Pet {
/*** @var string */
private $type;
public function __construct(string $type) {
$this->type = $type;
}
public function getPetType() : string {
return $this->type;
}
public function __toString() {
return json_encode([
'type' => $this->type
]);
}
}
* Cat, Dog 继承 Pet
** Cat.php
<?php
/**
* Created by PhpStorm.
* User: Mch
* Date: 9/24/18
* Time: 3:41 PM
*/
namespace stack\dogcat;
class Cat extends Pet {
public function __construct() {
parent::__construct("cat");
}
}
** Dog.php
<?php
/**
* Created by PhpStorm.
* User: Mch
* Date: 9/24/18
* Time: 3:38 PM
*/
namespace stack\dogcat;
class Dog extends Pet {
public function __construct() {
parent::__construct("dog");
}
}
* Pet包装类 PetWrapper, $id 记录入队的先后顺序
<?php
/**
* Created by PhpStorm.
* User: Mch
* Date: 9/24/18
* Time: 3:42 PM
*/
namespace stack\dogcat;
class PetWrapper {
/** @var Pet */
protected $pet;
/** @var int */
protected $id = 1;
public function __construct(Pet $pet, int $id) {
$this->pet = $pet;
if (is_null($id)) {$id = time();}
$this->id = $id;
// debug
// echo json_encode(['id' => $this->id, 'type' => $this->pet->getPetType(),]).PHP_EOL;
}
public function getPet() : Pet {
return $this->pet;
}
public function getId() : int {
return $this->id;
}
public function getEnterPetType() : string {
return $this->pet->getPetType();
}
public function __toString() {
return json_encode([
'id' => $this->id,
'type' => $this->pet->getPetType()
]);
}
}
* DogCatQueue.php
<?php
/**
* Created by PhpStorm.
* User: Mch
* Date: 9/24/18
* Time: 3:46 PM
*/
namespace stack\dogcat;
class DogCatQueue {
/** @var \SplQueue<PetWrapper> */
protected $dogQ;
/** @var \SplQueue<PetWrapper> */
protected $catQ;
/** @var int */
protected $count;
public function __construct() {
$this->dogQ = new \SplQueue();
$this->catQ = new \SplQueue();
$this->count = 0;
}
/**
* 将Cat或者Dog类的实例放入队列中
* @param Pet $pet
*/
public function enqueue(Pet $pet) {
if (strcmp($pet->getPetType(), "dog")===0) {
$this->dogQ->enqueue(new PetWrapper($pet, $this->count++));
} else if (strcmp($pet->getPetType(), "cat")===0) {
$this->catQ->enqueue(new PetWrapper($pet, $this->count++));
} else {
throw new \RuntimeException("Error, neither dog nor cat");
}
}
private static function front(\SplQueue $q) : PetWrapper {
return $q->offsetGet(0);
}
public function dequeue() : PetWrapper {
if (!$this->dogQ->isEmpty() && !$this->catQ->isEmpty()) {
if (self::front($this->dogQ)->getId() < self::front($this->catQ)->getId()) {
return $this->dogQ->dequeue();
} else {
return $this->catQ->dequeue();
}
} else if (!$this->dogQ->isEmpty()) {
return $this->dogQ->dequeue();
} else if (!$this->catQ->isEmpty()) {
return $this->catQ->dequeue();
} else {
throw new \RuntimeException("Error, the queue is empty!");
}
}
/**
* 将队列中所有的实例按照队列的先后顺序依次弹出
* @return Pet
*/
public function dequeueAny() : Pet {
return $this->dequeue()->getPet();
}
/**
* 将队列中Dog类的实例按照队列的先后顺序依次弹出
* @return Dog
*/
public function dequeueDog() : Dog {
if (!$this->isDogQueueEmpty()) {
return $this->dogQ->dequeue()->getPet();
}
throw new \RuntimeException("Dog queue is empty!");
}
public function dequeueCat() : Cat {
if (!$this->isDogQueueEmpty()) {
return $this->catQ->dequeue()->getPet();
}
throw new \RuntimeException("Cat queue is empty!");
}
/**
* 检查队列中是否还有Dog或者Cat的实例
* @return bool
*/
public function isEmpty() : bool {
return $this->dogQ->isEmpty() && $this->catQ->isEmpty();
}
/**
* 检查队列中是否有Dog类的实例
* @return bool
*/
public function isDogQueueEmpty() : bool {
return $this->dogQ->isEmpty();
}
/**
* 检查队列中是否有cat类的实例
* @return bool
*/
public function isCatQueueEmpty() : bool {
return $this->catQ->isEmpty();
}
public static function forEach(\SplQueue $q, callable $handler) {
$q->rewind();
while ($q->valid()) {
call_user_func($handler, $q->current());
$q->next();
}
}
public function __toString() : string {
$sCat = "[cat queue]: \n";
self::forEach($this->catQ, function(PetWrapper $petWrapper) use (&$sCat) {
$sCat .= $petWrapper->__toString().PHP_EOL;
});
$sDog = "[dog queue]: \n";
self::forEach($this->dogQ, function(PetWrapper $petWrapper) use (&$sDog) {
$sDog .= $petWrapper->__toString().PHP_EOL;
});
return $sCat.$sDog;
}
}
* 注册自动加载 autoload.php
<?php
$prefixList = ['stack\\dogcat', 'stack'];
array_walk($prefixList, function($prefix) {
spl_autoload_register(function($class) use ($prefix) {
$base_dir = __DIR__ . DIRECTORY_SEPARATOR. str_replace('\\', '/', $prefix);
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
$relative_class = substr($class, $len);
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
if (!file_exists($file)) {
throw new InvalidArgumentException($file.' does not exist');
}
require $file;
});
}, null);
* index.php
<?php
/**
* Created by PhpStorm.
* User: Mch
* Date: 9/24/18
* Time: 3:38 PM
*/
include './autoload.php';
use stack\dogcat\DogCatQueue;
use stack\dogcat\Dog;
use stack\dogcat\Cat;
// $number = rand(1, 255);
// echo $number.PHP_EOL;
$number = 217;
$q = new DogCatQueue();
while ($number) {
$isDog = $number & 0x01;
$number >>= 1;
$pet = $isDog ? new Dog() : new Cat();
$q->enqueue($pet);
}
echo '---------------------'.PHP_EOL;
echo $q;
echo '---------------------'.PHP_EOL;
// while (!$q->isEmpty()) {echo $q->dequeue().PHP_EOL;}
echo $q->dequeueCat().PHP_EOL;
echo $q->dequeueCat().PHP_EOL;
echo $q->dequeueDog().PHP_EOL;
while (!$q->isEmpty()) {echo $q->dequeue().PHP_EOL;}
* run test:
$ php index.php
---------------------
[cat queue]:
{"id":1,"type":"cat"}
{"id":2,"type":"cat"}
{"id":5,"type":"cat"}
[dog queue]:
{"id":0,"type":"dog"}
{"id":3,"type":"dog"}
{"id":4,"type":"dog"}
{"id":6,"type":"dog"}
{"id":7,"type":"dog"}
---------------------
{"type":"cat"}
{"type":"cat"}
{"type":"dog"}
{"id":3,"type":"dog"}
{"id":4,"type":"dog"}
{"id":5,"type":"cat"}
{"id":6,"type":"dog"}
{"id":7,"type":"dog"}