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

调用getData()报null错误:已初始化$api为何仍未定义?

问题

我是开发领域新手,请多包涵。我编写了一个包含若干方法的类,使用Workerman启动服务器,希望在服务器启动时通过function load()加载CSV数据,之后在API请求时根据传入的$key返回对应数据。

CSV数据如下:

doctor,31234-32223
police officer,342-341
firefighter,543-3345
worker,12223
developer,120045

我编写的App类代码如下:

class App 
{

    public $getPair = null;
    public $dataToLoad= []; 
    protected $dispatcher = null;

   /**
     * start
     */
    public function start()
    {
        $this->dispatcher = \FastRoute\simpleDispatcher(function(\FastRoute\RouteCollector $r) {
            foreach ($this->routeInfo as $method => $callbacks) {
                foreach ($callbacks as $info) {
                    $r->addRoute($method, $info[0], $info[1]);
                }
            }
        });

        \Workerman\Worker::runAll();
    }

    function load()
    {
        $files = "load.csv";
                    
        foreach($files as $file) {
            if (($handle = fopen($file, "r")) !== FALSE) {
                while (($data = fgetcsv($handle, 4096, ",")) !== FALSE) {
                    $dataToLoad[$data[1]] = $data[0]; 
                }
                fclose($handle);
            }
        }

        return $this->dataToLoad;
    }

    function getData($getPair) {
        foreach ($this->dataToLoad as $key => $value){
            if($getPair === $key){
                return array($key.','.$value);
            } else {
                echo "missing";
            }
        } 
    }

    /**
     * @param TcpConnection $connection
     * @param Request $request
     * @return null
     */
    public function onMessage($connection, $request)
    {
        static $callbacks = [];
        try {
            $path = $request->path();
            $method = $request->method();
            $key = $method . $path;
            $callback = $callbacks[$key] ?? null;
            if ($callback) {
                $connection->send($callback($request));
                return null;
            }

            $ret = $this->dispatcher->dispatch($method, $path);
            if ($ret[0] === Dispatcher::FOUND) {
                $callback = $ret[1];
                if (!empty($ret[2])) {
                    $args = array_values($ret[2]);
                    $callback = function ($request) use ($args, $callback) {
                        return $callback($request, ... $args);
                    };
                }
                $callbacks[$key] = $callback;
                $connection->send($callback($request));
                return true;
            } else {
                $connection->send(new Response(404, [], '<h1>404 Not Found</h1>'));
            }
        } catch (\Throwable $e) {
            $connection->send(new Response(500, [], (string)$e));
        }
    }
}

index.php代码如下:

use Mark\App;

$api = new App('http://0.0.0.0:3000');
$api->count = 4; // process count
$api->load(); //load data

$api->get('/key/{key}', function ($request, $key) {
    return $api->getData("doctor");
});

$api->start();

错误信息:

Error: Call to a member function getData() on null
PHP Warning: Undefined variable $api

明明我已通过new App()初始化了$api,为何会出现getData()调用时为null、$api未定义的问题?注:服务器可正常启动且无报错。

解决方案

1. 核心问题:闭包变量作用域

路由回调函数默认不会继承外部作用域的$api变量,所以当请求触发回调时,PHP找不到$api变量,导致报错。

修复方法:在闭包中通过use关键字显式引入$api,同时把固定的"doctor"改成请求传入的$key参数:

$api->get('/key/{key}', function ($request, $key) use ($api) {
    return $api->getData($key);
});

2. 修复App类中的逻辑错误

除了作用域问题,你的App类还有几处错误需要修正:

(1) load方法的错误

  • $files = "load.csv";是字符串,不能用foreach遍历,直接使用文件名即可
  • 给类属性赋值时必须加$this->,否则会创建局部变量,无法更新类的$dataToLoad属性

修正后的load方法:

function load()
{
    $file = "load.csv";
    if (($handle = fopen($file, "r")) !== FALSE) {
        while (($data = fgetcsv($handle, 4096, ",")) !== FALSE) {
            $this->dataToLoad[$data[1]] = $data[0]; 
        }
        fclose($handle);
    }
    return $this->dataToLoad;
}

(2) getData方法的逻辑问题

  • 原循环会在第一个不匹配的key就输出"missing",导致多次无效输出,且无法正确处理找不到key的情况
  • 可以直接利用数组索引查找,不需要循环遍历

修正后的getData方法:

function getData($getPair) {
    if (isset($this->dataToLoad[$getPair])) {
        return [$getPair . ',' . $this->dataToLoad[$getPair]];
    }
    return ["missing: {$getPair}"];
}

3. 最终修正后的index.php

use Mark\App;

$api = new App('http://0.0.0.0:3000');
$api->count = 4; // process count
$api->load(); //load data

$api->get('/key/{key}', function ($request, $key) use ($api) {
    return $api->getData($key);
});

$api->start();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 10:46:16