解决 pcntl 相关函数报错的问题

问题

macOS环境中,命令行运行php artisan horizon报错:

Call to undefined function Laravel\Horizon\pcntl_async_signals()

原因1:缺少pcntl扩展

首先查看pcntl扩展是否已经安装:

php --ri pcntl

如果未安装,为命令行使用的 PHP 安装pcntl扩展后重试。

原因2:函数被禁用

如果原因1已经排除,可能是相关函数被禁用。 找出当前使用的php.ini文件:

php --ini
# 输出
Loaded Configuration File:  /Library/Application Support/appsolute/MAMP PRO/conf/php7.4.1.ini

打开当前使用的php.ini文件,即: /Library/Application Support/appsolute/MAMP PRO/conf/php7.4.1.ini,搜索disable_functions,查看pcntl相关的函数是否被禁用。

原因3:多个 php.ini 文件的原因

如果原因1、原因2都已经排除,可能是因为加载了多个php.ini文件。

解决方案

查看现有的php.ini文件:

php --ini
# 输出
Configuration File (php.ini) Path: /Applications/MAMP/bin/php/php7.4.1/conf
Loaded Configuration File:         /Library/Application Support/appsolute/MAMP PRO/conf/php7.4.1.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

可以看到相关的php.ini文件有多个:

/Applications/MAMP/bin/php/php7.4.1/conf 目录下的 php.ini文件
/Library/Application Support/appsolute/MAMP PRO/conf/php7.4.1.ini

找出这些php.ini文件,确保每个php.ini文件中都有这样一行:

extension=pcntl.so

排查思路

如果以上三个解决方案都不可行,可以按以下思路排查。

定位到抛出异常的 PHP 文件,比如作者遇到的是以下代码抛出的异常:

    protected function listenForSignals()
    {
        pcntl_async_signals(true);
     ......

加入代码,输出这段代码使用的 PHP 信息:

    protected function listenForSignals()
    {
        # 输出PHP版本
        dump(PHP_VERSION);
        # 输出pcntl扩展是否已经加载
        dump(extension_loaded('pcntl'));
        # 输出当前使用的php.ini文件
        dump(php_ini_loaded_file());

        pcntl_async_signals(true);
        ......

输出:

Horizon started successfully.
"7.4.1"
true
"/Library/Application Support/appsolute/MAMP PRO/conf/php7.4.1.ini"
"7.4.1"
false
"/Applications/MAMP/bin/php/php7.4.1/conf/php.ini"

   Error 

  Call to undefined function Laravel\Horizon\pcntl_async_signals()

可以看出第二个php.ini文件中,没有加载pcntl扩展。