This article mainly introduces the PHP Daemon class, which is a special process running in the background. It is independent of the control terminal and periodically executes a task or waits to process some events. Daemon is a very useful process. Php can also implement Daemon class implemented by PHP. You can implement a queue or a scheduled task that is out of crontab on the server.
When used, it inherits from this class and overwrites the _ doTask method, which is initialized and executed through main.
<? Php class Daemon {const DLOG_TO_CONSOLE = 1; const DLOG_NOTICE = 2; const DLOG_WARNING = 4; const DLOG_ERROR = 8; const DLOG_CRITICAL = 16; const DAPC_PATH = '/tmp/done '; /*** User ID ** @ var int */public $ userID = 65534; // nobody/*** Group ID ** @ var integer */public $ groupID = 65533; // nobody/*** Terminate daemon when set identity failure? ** @ Var bool * @ since 1.0.3 */public $ requireSetIdentity = false; /*** Path to PID file ** @ var string * @ since 1.0.1 */public $ pidFileLocation = '/tmp/daemon. pid ';/*** processLocation * process information record directory ** @ var string */public $ processLocation = ''; /*** processHeartLocation * process heartpackage file ** @ var string */public $ processHeartLocation = ''; /*** Home path ** @ var string * @ since 1.0 */public $ h OmePath = '/';/*** Current process ID ** @ var int * @ since 1.0 */protected $ _ pid = 0; /*** Is this process a children ** @ var boolean * @ since 1.0 */protected $ _ isChildren = false; /*** Is daemon running ** @ var boolean * @ since 1.0 */protected $ _ isRunning = false; /*** Constructor *** @ return void */public function _ construct () {error_reporting (0); set_time_limit (0); ob_implicit_flu Sh (); register_shutdown_function (array (& $ this, 'releasedaemon');}/*** start process *** @ return bool */public function main () {$ this-> _ logMessage ('starting daemon'); if (! $ This-> _ daemonize () {$ this-> _ logMessage ('could not start daemon', self: DLOG_ERROR); return false ;} $ this-> _ logMessage ('running... '); $ this-> _ isRunning = true; while ($ this-> _ isRunning) {$ this-> _ doTask ();} return true ;} /*** stop the process ** @ return void */public function stop () {$ this-> _ logMessage ('stoping daemon '); $ this-> _ isRunning = false;}/*** Do task ** @ return void */protected function _ DoTask () {// override this method}/*** _ logMessage * Record log ** @ param string message * @ param integer level * @ return void */protected function _ logMessage ($ msg, $ level = self: DLOG_NOTICE) {// override this method}/*** Daemonize ** Several rules or characteristics that most daemons possess: * 1) check is daemon already running * 2) Fork child process * 3) Sets identity * 4) Make current proces S a session laeder * 5) Write process ID to file * 6) Change home path * 7) umask (0) ** @ access private * @ since 1.0 * @ return void */private function _ daemonize () {ob_end_flush (); if ($ this-> _ isDaemonRunning ()) {// Deamon is already running. exiting return false;} if (! $ This-> _ fork () {// Coudn't fork. Exiting. return false;} if (! $ This-> _ setIdentity () & $ this-> requireSetIdentity) {// Required identity set failed. Exiting return false;} if (! Posix_setsid () {$ this-> _ logMessage ('could not make the current process a session leader ', self: DLOG_ERROR); return false;} if (! $ Fp = fopen ($ this-> pidFileLocation, 'w') {$ this-> _ logMessage ('could not write to PID file', self: DLOG_ERROR ); return false;} else {fputs ($ fp, $ this-> _ pid); fclose ($ fp);} // write monitoring logs $ this-> writeProcess (); chdir ($ this-> homePath); umask (0); declare (ticks = 1); pcntl_signal (SIGCHLD, array (& $ this, 'sighandler ')); pcntl_signal (SIGTERM, array (& $ this, 'sighandler'); pcntl_signal (SIGUSR1, array (& $ this, 'Sighandler'); pcntl_signal (SIGUSR2, array (& $ this, 'sighandler'); return true ;} /*** Cheks is daemon already running ** @ return bool */private function _ isDaemonRunning () {$ oldPid = file_get_contents ($ this-> pidFileLocation); if ($ oldPid! = False & posix_kill (trim ($ oldPid), 0) {$ this-> _ logMessage ('daemon already running with PID :'. $ oldPid, (self: DLOG_TO_CONSOLE | self: DLOG_ERROR); return true ;}else {return false ;}} /*** Forks process *** @ return bool */private function _ fork () {$ this-> _ logMessage ('Forking... '); $ pid = pcntl_fork (); if ($ pid =-1) {// error $ this-> _ logMessage ('could not fork', self :: DLOG_ERROR); return False;} elseif ($ pid) {// parent process $ this-> _ logMessage ('killing parent'); exit ();} else {// fork sub-process $ this-> _ isChildren = true; $ this-> _ pid = posix_getpid (); return true ;}} /*** Sets identity of a daemon and returns result *** @ return bool */private function _ setIdentity () {if (! Posix_setgid ($ this-> groupID) |! Posix_setuid ($ this-> userID) {$ this-> _ logMessage ('could not set identifi', self: DLOG_WARNING); return false ;} else {return true;}/*** Signals handler ** @ access public * @ since 1.0 * @ return void */public function sigHandler ($ sigNo) {switch ($ sigNo) {case SIGTERM: // Shutdown $ this-> _ logMessage ('shutdown signal '); exit (); break; case SIGCHLD: // Halt $ this-> _ logMessage ('halt signal '); While (pcntl_waitpid (-1, $ status, WNOHANG)> 0); break; case SIGUSR1: // User-defined $ this-> _ logMessage ('User-defined signal 1'); $ this-> _ sigHandlerUser1 (); break; case SIGUSR2: // User-defined $ this-> _ logMessage ('User-defined signal 2'); $ this-> _ sigHandlerUser2 (); break ;}} /*** Signals handler: USR1 * is mainly used to regularly clear the cached dns resolution records of domain names in each process ** @ return void */protected function _ sigHandlerUser1 () {apc_c Lear_cache ('user');}/*** Signals handler: USR2 * used to write the heartbeat package file ** @ return void */protected function _ sigHandlerUser2 () {$ this-> _ initProcessLocation (); file_put_contents ($ this-> processHeartLocation, time (); return true ;} /*** Releases daemon pid file * This method is called on exit (destructor like) ** @ return void */public function releaseDaemon () {if ($ this-> _ isChildren & is_file ($ this-> PidFileLocation) {$ this-> _ logMessage ('releasing daemon'); unlink ($ this-> pidFileLocation );}} /*** writeProcess ** writes information about the current process to the monitoring log. The script also scans the data sending signals of the monitoring log, if no response is received, restart the process ** @ return void */public function writeProcess () {// initialize proc $ this-> _ initProcessLocation (); $ command = trim (implode ('', $ _ SERVER ['argv']); // specify the process directory $ processDir = $ this-> processLocation. '/'. $ this-> _ pid; $ processCmdFile = $ proc EssDir. '/cmd'; $ processPwdFile = $ processDir.'/pwd'; // if (! Is_dir ($ this-> processLocation) {mkdir ($ this-> processLocation, 0777); chmod ($ processDir, 0777 );} // query duplicate process records $ pDirObject = dir ($ this-> processLocation); while ($ pDirObject & ($ pid = $ pDirObject-> read ())! = False) {if ($ pid = '.' | $ pid = '..' | intval ($ pid )! = $ Pid) {continue;} $ pDir = $ this-> processLocation. '/'. $ pid; $ pCmdFile = $ pDir. '/cmd'; $ pPwdFile = $ pDir. '/pwd'; $ pHeartFile = $ pDir. '/heart'; // run the cmd check to start the process with the same parameters if (is_file ($ pCmdFile) & trim (file_get_contents ($ pCmdFile) ==$ command) {unlink ($ pCmdFile); unlink ($ pPwdFile); unlink ($ pHeartFile); // delete the cache usleep (1000); rmdir ($ pDir );}} // New process directory if (! Is_dir ($ processDir) {mkdir ($ processDir, 0777); chmod ($ processDir, 0777) ;}// write command parameter file_put_contents ($ processCmdFile, $ command ); file_put_contents ($ processPwdFile, $ _ SERVER ['pwd']); // The written file has the cache usleep (1000); return true ;} /*** _ initProcessLocation * initialization ** @ return void */protected function _ initProcessLocation () {$ this-> processLocation = ROOT_PATH. '/app/data/proc'; $ this-> processHeartLocation = $ this-> processLocation. '/'. $ this-> _ pid. '/heart ';}}