pulsar 毕竟是一个新生代的工具,PHP的客户端链接库几乎可以说没有,找了半天才只找到一个: pulsar-client-phpcpp 那么我们就来安装这个PHP扩展,我使用的是 MacOS 所以就以这个环境来安装。

根据README.MD,先看看扩展的依赖情况:

然后就是先安装依赖,最后再安装 pulsar-client-cpp

安装 Pulsar C++ client library

Pulsar C++ client library 是 Pulsar 官方提供的一个 C++ 的客户端链接库,用来连接 Pulsar 的。

在 MacOS 下我们有方便的工具 brew ,先来搜索看看 brew search 有没有有,有的就可以直接安装了

~ brew search pulsar
==> Formulae
libpulsar ✔

可以看到我们可以正常找到了 libpulsar ,那么就安装就行:

~ brew install libpulsar
==> Downloading https://mirrors.aliyun.com/homebrew/homebrew-bottles/bottles/libpulsar-2.7.1.big_sur.bottle.1.tar.gz
Already downloaded: /Users/mrcong/Library/Caches/Homebrew/downloads/23ecf52715abd669569c82f1a35be1c29bc76fe9ba971791f479a87a4505cb9b--libpulsar-2.7.1.big_sur.bottle.1.tar.gz
==> Reinstalling libpulsar
==> Pouring libpulsar-2.7.1.big_sur.bottle.1.tar.gz
?  /usr/local/Cellar/libpulsar/2.7.1: 54 files, 19.9MB

编译安装 PHP-CPP

PHP-CPP是一个用于开发PHP扩展的C++库,依赖这个库证明 pulsar-client-phpcpp 是使用了这个 C++ 库来开发的。

//git 克隆下来
~ git clone https://github.com/CopernicaMarketingSoftware/PHP-CPP.git
Cloning into 'PHP-CPP'...
remote: Enumerating objects: 5992, done.
remote: Total 5992 (delta 0), reused 0 (delta 0), pack-reused 5992
Receiving objects: 100% (5992/5992), 1.92 MiB | 2.16 MiB/s, done.
Resolving deltas: 100% (4224/4224), done.
//编译
~ make
//编译好后直接安装
~ sudo make install

编译安装 pulsar-client-cpp 扩展

安装好了 Pulsar C++ client libraryPHP-CPP 后,就来编译安装 pulsar-client-cpp 扩展。

 ~ git clone git@github.com:oraoto/pulsar-client-phpcpp.git
 ~ cd pulsar-client-phpcpp
 ~ make -j4  // -j4 里面的 4是指 CPU的核数,可以提升编译速度

本身以为也一样顺利的,但是没想到在这一步居然出现了编译错误的问题。 ̄□ ̄||

过程中遇到了错误,信息如下:

g++ -Wall -shared -O2 -o pulsar-phpcpp.so src/Client.o src/Consumer.o src/ConsumerConfiguration.o src/Message.o src/MessageBuilder.o src/MessageId.o src/Producer.o src/Pulsar.o -lphpcpp -lpulsar
Undefined symbols for architecture x86_64:
  "MessageId::latest(Php::Parameters&)", referenced from:
      void Php::ZendCallable::invoke<&(MessageId::latest(Php::Parameters&))>(_zend_execute_data*, _zval_struct*) in MessageId.o
  "MessageId::earliest(Php::Parameters&)", referenced from:
      void Php::ZendCallable::invoke<&(MessageId::earliest(Php::Parameters&))>(_zend_execute_data*, _zval_struct*) in MessageId.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [pulsar-phpcpp.so] Error 1

pulsar-client-phpcpp 仓库的 ISSUE 看了一下,发现去年就有人提到了 MacOS 下编译不成功。然后作者还说不一定能解决,?,好尴尬,咋办了?

这对于一个没写过C++项目的人来说,是在不愿意去看这个错误信息啊。 考虑换一个扩展? 但是已经没得换了,搜索了一圈,发现只有这一个 PHP 的 Pulsar 扩展。

脑阔痛,要放弃么?换 Go 来?

总感觉不太甘心啊。PHP 是时间上最强大的语言(笑),所以坚决不能放弃。

既然都不想放弃,那么硬着头皮上吧。 不折腾会死星人不能这样服输,拿出当年大学学的那点 C++ 基础来看看能不能解决这个报错。

首先是 Undefined symbols for architecture x86_64 ,符号引用错误?

从编译日志看 g++ -Wall -shared -O2 -o pulsar-phpcpp.so src/Client.o src/Consumer.o src/ConsumerConfiguration.o src/Message.o src/MessageBuilder.o src/MessageId.o src/Producer.o src/Pulsar.o -lphpcpp -lpulsar 来看,编译的文件里面是有 src/MessageId.o 不是少文件的问题。

换一个关键词 "MessageId::earliest(Php::Parameters&)", referenced from? 按这个说明是没有或者访问不到这个静态方法?打开 MessageId.cpp 看看

去找了PHP-CPP的文档,提到类方法需要导出,再回来看 MessageId.cpp 文件,类方法也都有做导出

void registerMessageId(Php::Namespace &pulsarNamespace)
{
    Php::Class<MessageId> messageId("MessageId");
    messageId.method<&MessageId::earliest>("earliest");
    messageId.method<&MessageId::latest>("latest");
    messageId.method<&MessageId::getTopicName>("getTopicName");
    messageId.method<&MessageId::serialize>("serialize");
    messageId.method<&MessageId::deserialize>("deserialize");
}

只是唯一不同的有一个点,就是有的静态函数是 MessageId:: 做前缀,有的是使用 static 做前缀,这个有什么不一样么?从报错信息看,提示引用错误的都是使用 static 做装饰前缀的,难道是没使用 MessageId:: 作为前缀的被当成了私有方法?

改天得回去看看继续学学C和C++了。

那么试试改ta,在 void registerMessageId(Php::Namespace &pulsarNamespace) 顶端新增两新方法,使用 MessageId:: 做装饰前缀~~

Php::Value MessageId::earliest(Php::Parameters &params) { return ::earliest(); }
Php::Value MessageId::latest(Php::Parameters &params) { return ::latest(); }

然后再来重新编译

 ~ make clean //清理一下上一次的编译结果
 ~ make -j4  // 嘿嘿嘿,完美通过了

执行完 make 就已经生成了 pulsar-phpcpp.so 文件了,把这个文件拷贝到php 7.4 的扩展目录下,在 php.ini 里面启用这个动态扩展,然后重启 PHP,去看看

phpinfo

嘿嘿嘿~,成功了。 看来我是瞎猫碰上死耗子了…… 后面就是来测试一下生产消息和消费消息了。

消息生产者

在安装 pulsar-client-phpcpp 扩展后,我们就可以使用了,我们先来写一个生产者,往消息系统里面生产数据:

<?php

use Pulsar\Client;
use Pulsar\MessageBuilder;

date_default_timezone_set('PRC');

$client = new Client("pulsar://127.0.0.1:6650");

$producer = $client->createProducer("persistent://public/default/test001/topic");

while (true)
{
    $data    = [
        'body' => ['time' => date('Y-m-d H:i:s')],
    ];
    $builder = new MessageBuilder();
    $builder->setContent(json_encode($data));
    $message = $builder->setDeliverAfter(5000)->build();
    $producer->send($message);
    unset($builder, $message);
    echo date('Y-m-d H:i:s') . ' done' . PHP_EOL;
    usleep(10);
}

消息消费者

生产完了数据,我们就来消费数据,写一个消费者

<?php
use Pulsar\Client;
use Pulsar\Consumer;
use Pulsar\ConsumerConfiguration;
use Pulsar\MessageBuilder;

$client = new Client("pulsar://127.0.0.1:6650");

$config = new ConsumerConfiguration();
$config->setConsumerType(Consumer::ConsumerShared);

$consumer = $client->subscribe("persistent://public/default/test001/topic", "consumer-1", $config);
while (true)
{
    $message = $consumer->receive();
    var_dump($message->getDataAsString());
    $consumer->acknowledge($message);
}

到这,就OK了,能正常使用了。然后关于 Pulsar 连接的配置属性的等,后面会开新的文章说明。

Pulsar PHP IDE Helpers

这个扩展在 PHPStorm 里面没有语法提示,很难受,于是顺手做了一个 pulsar-php-ide-helpers

怎么使用呢?

先把项目克隆下来

 ~ git clone https://github.com/cong5/pulsar-php-ide-helpers ~/Downloads/pulsar-php-ide-helpers

然后在 PHPStorm 项目右侧项目文件栏里面,拉到底部,找到 External Libraries ,右键选择 Configure PHP Include Paths... ,选择上这个项目的路径就行。