* 目录结构
猫狗队列 PHP 注册自动加载 autoload.php_stack

* 基类 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"}