用PHP实现的Daemon类。可以在服务器上实现队列或者脱离 crontab 的计划任务。
使用的时候,继承于这个类,并重写 _doTask 方法,通过 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/daemon_apc_keys'; /** * 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 * 进程信息记录目录 * * @var string */ public $processLocation = ''; /** * processHeartLocation * 进程心跳包文件 * * @var string */ public $processHeartLocation = ''; /** * Home path * * @var string * @since 1.0 */ public $homePath = '/'; /** * 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_flush(); register_shutdown_function(array(&$this, 'releaseDaemon')); } /** * 启动进程 * * @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; } /** * 停止进程 * * @return void */ public function stop() { $this->_logMessage('Stoping daemon'); $this->_isRunning = false; } /** * Do task * * @return void */ protected function _doTask() { // override this method } /** * _logMessage * 记录日志 * * @param string 消息 * @param integer 级别 * @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 process 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); } // 写入监控日志 $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) { // 出错 $this->_logMessage('Could not fork', self::DLOG_ERROR); return false; } elseif ($pid) { // 父进程 $this->_logMessage('Killing parent'); exit(); } else { // fork的子进程 $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 identity', 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 * 主要用于定时清理每个进程里被缓存的域名dns解析记录 * * @return void */ protected function _sigHandlerUser1() { apc_clear_cache('user'); } /** * Signals handler: USR2 * 用于写入心跳包文件 * * @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 * 将当前进程信息写入监控日志,另外的脚本会扫描监控日志的数据发送信号,如果没有响应则重启进程 * * @return void */ public function writeProcess() { // 初始化 proc $this->_initProcessLocation(); $command = trim(implode(' ', $_SERVER['argv'])); // 指定进程的目录 $processDir = $this->processLocation . '/' . $this->_pid; $processCmdFile = $processDir . '/cmd'; $processPwdFile = $processDir . '/pwd'; // 所有进程所在的目录 if (!is_dir($this->processLocation)) { mkdir($this->processLocation, 0777); chmod($processDir, 0777); } // 查询重复的进程记录 $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'; // 根据cmd检查启动相同参数的进程 if (is_file($pCmdFile) && trim(file_get_contents($pCmdFile)) == $command) { unlink($pCmdFile); unlink($pPwdFile); unlink($pHeartFile); // 删目录有缓存 usleep(1000); rmdir($pDir); } } // 新进程目录 if (!is_dir($processDir)) { mkdir($processDir, 0777); chmod($processDir, 0777); } // 写入命令参数 file_put_contents($processCmdFile, $command); file_put_contents($processPwdFile, $_SERVER['PWD']); // 写文件有缓存 usleep(1000); return true; } /** * _initProcessLocation * 初始化 * * @return void */ protected function _initProcessLocation() { $this->processLocation = ROOT_PATH . '/app/data/proc'; $this->processHeartLocation = $this->processLocation . '/' . $this->_pid . '/heart'; } }

PHP在現代Web開發中仍然重要,尤其在內容管理和電子商務平台。 1)PHP擁有豐富的生態系統和強大框架支持,如Laravel和Symfony。 2)性能優化可通過OPcache和Nginx實現。 3)PHP8.0引入JIT編譯器,提升性能。 4)雲原生應用通過Docker和Kubernetes部署,提高靈活性和可擴展性。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP在現代編程中仍然是一個強大且廣泛使用的工具,尤其在web開發領域。 1)PHP易用且與數據庫集成無縫,是許多開發者的首選。 2)它支持動態內容生成和麵向對象編程,適合快速創建和維護網站。 3)PHP的性能可以通過緩存和優化數據庫查詢來提升,其廣泛的社區和豐富生態系統使其在當今技術棧中仍具重要地位。

在PHP中,弱引用是通過WeakReference類實現的,不會阻止垃圾回收器回收對象。弱引用適用於緩存系統和事件監聽器等場景,需注意其不能保證對象存活,且垃圾回收可能延遲。

\_\_invoke方法允許對象像函數一樣被調用。 1.定義\_\_invoke方法使對象可被調用。 2.使用$obj(...)語法時,PHP會執行\_\_invoke方法。 3.適用於日誌記錄和計算器等場景,提高代碼靈活性和可讀性。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

記事本++7.3.1
好用且免費的程式碼編輯器

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

SublimeText3漢化版
中文版,非常好用