You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下用php-smpp库报错:call_user_func找不到printDebug函数求助

解决php-smpp库回调函数找不到的问题

问题现象

在Windows环境使用php-smpp的windows兼容版本开发SMPP短信发送功能时,触发报错:

call_user_func(): Argument #1 ($callback) must be a valid callback, function "printDebug" not found or invalid function name

问题原因

你把printDebug函数定义在sendSmsSmpp方法内部,属于局部函数,而SmppClient和TSocket类在外部调用这个回调时,PHP的函数查找机制无法定位到该局部函数,导致回调无效。

解决方案

把printDebug改为控制器类的成员方法,并以数组格式传递回调(PHP中类方法的回调格式为[$实例, '方法名'])。

修正后的控制器代码

<?php
namespace App\Http\Controllers;
use Exception;
use GsmEncoder;
use SMPP;
use SmppAddress;
use SmppClient;
use TSocket;

$GLOBALS['SMPP_ROOT'] = dirname(__FILE__); 
require_once $GLOBALS['SMPP_ROOT'].'/protocol/smppclient.class.php';
require_once $GLOBALS['SMPP_ROOT'].'/protocol/gsmencoder.class.php';
require_once $GLOBALS['SMPP_ROOT'].'/transport/tsocket.class.php';

class apiSmsSmppController extends Controller{
    
    // 移为类的公共成员方法
    public function printDebug($str) {
        echo date('Ymd H:i:s ').$str."\r\n";
    }
    
    public function sendSmsSmpp($message,$tel){
        try {
            // 传递回调改为数组格式:[$this, '方法名']
            $transport = new TSocket('xxx.xxx.xx.xx',2775,false,[$this, 'printDebug']);
            $transport->setRecvTimeout(10000);
            $transport->setSendTimeout(10000);
            // 同样修改这里的回调参数
            $smpp = new SmppClient($transport,[$this, 'printDebug']);
            
            $smpp->debug = true;        
            $transport->setDebug(true); 
            
            $transport->open();
            $smpp->bindTransmitter("xxxxx","xxxx");
            
            $message = 'H€llo world';
            $encodedMessage = GsmEncoder::utf8_to_gsm0338($message);
            $from = new SmppAddress(GsmEncoder::utf8_to_gsm0338('SMPP Tést'),SMPP::TON_ALPHANUMERIC);
            $to = new SmppAddress(22670530377,SMPP::TON_INTERNATIONAL,SMPP::NPI_E164);
            
            $smpp->sendSMS($from,$to,$encodedMessage);
            
            $smpp->close();
            
        } catch (Exception $e) {
            try {
                $smpp->close();
            } catch (Exception $ue) {
                // 调用类内方法
                $this->printDebug("Failed to unbind; '".$ue->getMessage()."' closing transport");
                if ($transport->isOpen()) $transport->close();
            }
            throw $e; 
        }
    }
}
?>

补充说明

smppclient.class中通过call_user_func($this->debugHandler, ...)调用回调,PHP对回调的有效性要求:

  • 全局函数直接传字符串函数名
  • 类实例方法传[$实例对象, '方法名']
  • 静态方法传[类名::class, '静态方法名']

如果不想改为类方法,也可以把printDebug定义在命名空间之外(全局作用域),但在Laravel框架中推荐使用类成员方法的方式,更符合代码规范。

内容的提问来源于stack exchange,提问作者le prince

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 20:07:03