Using pcntl_fork() can be a little tricky in some situations.  For fast jobs, a child can finish processing before the parent process has executed some code related to the launching of the process.  The parent can receive a signal before it's ready to handle the child process' status.  To handle this scenario, I add an id to a "queue" of processes in the signal handler that need to be cleaned up if the parent process is not yet ready to handle them.
<?php
declare(ticks=1);
class JobDaemon{
    public $maxProcesses = 25;
    protected $jobsStarted = 0; 
    protected $currentJobs = array();
    protected $signalQueue=array();    
    protected $parentPID;
    
    public function __construct(){
        echo "constructed \n";
        $this->parentPID = getmypid();
        pcntl_signal(SIGCHLD, array($this, "childSignalHandler"));
    }
    
    public function run(){
        echo "Running \n";
        for($i=0; $i<10000; $i++){
            $jobID = rand(0,10000000000000);
            $launched = $this->launchJob($jobID);
        }
        
        while(count($this->currentJobs)){
            echo "Waiting for current jobs to finish... \n";
            sleep(1);
        }
    }
    
    protected function launchJob($jobID){
        $pid = pcntl_fork();
        if($pid == -1){
            error_log('Could not launch new job, exiting');
            return false;
        }
        else if ($pid){
            $this->currentJobs[$pid] = $jobID;
            
            if(isset($this->signalQueue[$pid])){
                echo "found $pid in the signal queue, processing it now \n";
                $this->childSignalHandler(SIGCHLD, $pid, $this->signalQueue[$pid]);
                unset($this->signalQueue[$pid]);
            }
        }
        else{
            $exitStatus = 0; echo "Doing something fun in pid ".getmypid()."\n";
            exit($exitStatus);
        }
        return true;
    }
    
    public function childSignalHandler($signo, $pid=null, $status=null){
        
        if(!$pid){
            $pid = pcntl_waitpid(-1, $status, WNOHANG);
        }
        
        while($pid > 0){
            if($pid && isset($this->currentJobs[$pid])){
                $exitCode = pcntl_wexitstatus($status);
                if($exitCode != 0){
                    echo "$pid exited with status ".$exitCode."\n";
                }
                unset($this->currentJobs[$pid]);
            }
            else if($pid){
                echo "..... Adding $pid to the signal queue ..... \n";
                $this->signalQueue[$pid] = $status;
            }
            $pid = pcntl_waitpid(-1, $status, WNOHANG);
        }
        return true;
    }
}