[{"data":1,"prerenderedAt":2876},["ShallowReactive",2],{"blog-post-\u002Fblog\u002Fkafka-php-clients":3},{"id":4,"title":5,"body":6,"date":2861,"description":2862,"extension":2863,"meta":2864,"navigation":2865,"ogImage":2866,"ogImageHeight":2866,"ogImageWidth":2866,"path":2867,"pinned":2868,"seo":2869,"sitemap":2870,"stem":2871,"tags":2872,"__hash__":2875},"blog\u002Fblog\u002Fkafka-php-clients.md","Kafka PHP Clients 2026: php-rdkafka, Laravel & Symfony",{"type":7,"value":8,"toc":2816},"minimark",[9,34,42,45,50,211,215,218,240,247,258,264,275,281,288,292,298,560,567,573,579,582,605,610,803,809,811,818,822,937,942,945,963,967,1080,1085,1089,1093,1100,1105,1161,1166,1289,1298,1309,1313,1318,1337,1442,1453,1466,1477,1480,1483,1526,1533,1542,1546,1549,1554,1600,1605,1682,1685,1688,1691,1775,1779,1782,1788,1798,1802,1864,1868,2014,2021,2025,2152,2159,2163,2292,2298,2310,2314,2410,2417,2421,2452,2455,2459,2469,2482,2486,2493,2499,2513,2521,2530,2534,2537,2546,2549,2553,2561,2564,2595,2599,2607,2622,2630,2637,2641,2645,2648,2652,2661,2665,2675,2679,2690,2694,2703,2706,2710,2722,2732,2735,2747,2750,2754,2763,2766,2769,2773,2776,2785,2788,2792,2798,2801,2804,2810,2813],[10,11,12,13,17,18,21,22,25,26,29,30,33],"p",{},"Most maintained PHP Kafka libraries are built on ",[14,15,16],"strong",{},"php-rdkafka",", the PECL extension that binds Confluent's librdkafka C library. ",[14,19,20],{},"Laravel Kafka",", ",[14,23,24],{},"Enqueue","'s Kafka transport, the Symfony Messenger transport ",[14,27,28],{},"koco\u002Fmessenger-kafka",", and ",[14,31,32],{},"php-kafka-lib"," all call it, so installing the extension is the first decision for Laravel, Symfony, and plain PHP projects alike.",[10,35,36,37],{},"A few options avoid the extension: pure PHP clients such as longlang\u002Fphpkafka, RoadRunner's Kafka driver, and HTTP through a REST Proxy. Each trades the extension for other limits; see ",[38,39,41],"a",{"href":40},"#can-you-use-kafka-without-php-rdkafka","Can you use Kafka without php-rdkafka?",[10,43,44],{},"This guide compares what each library does with your records when a send fails, a handler throws, or a process shuts down. It also covers Avro with Schema Registry and the trade-offs of producing from PHP-FPM.",[46,47,49],"h2",{"id":48},"quick-decision","Quick decision",[51,52,53,69],"table",{},[54,55,56],"thead",{},[57,58,59,63,66],"tr",{},[60,61,62],"th",{},"Situation",[60,64,65],{},"Best starting point",[60,67,68],{},"Why",[70,71,72,93,116,136,155,174,189],"tbody",{},[57,73,74,80,85],{},[75,76,77],"td",{},[14,78,79],{},"Laravel application",[75,81,82],{},[38,83,20],{"href":84},"#laravel-kafka-producers-and-consumers",[75,86,87,88,92],{},"Laravel producer and consumer APIs with retries and dead-letter topics. Failed records are committed and skipped by default; configure a dead-letter topic or ",[89,90,91],"code",{},"stopOnFailure()"," to keep them.",[57,94,95,100,105],{},[75,96,97],{},[14,98,99],{},"Symfony Messenger",[75,101,102],{},[38,103,28],{"href":104},"#symfony-messenger-kafka-koco-vs-enqueue",[75,106,107,108,111,112,115],{},"A Kafka transport for Messenger. Set ",[89,109,110],{},"enable.auto.offset.store"," to ",[89,113,114],{},"false"," so records are not auto-committed before handlers finish. Cooperative rebalancing and KIP-848 are not supported.",[57,117,118,123,129],{},[75,119,120],{},[14,121,122],{},"Plain PHP service or script",[75,124,125,128],{},[38,126,16],{"href":127},"#php-rdkafka"," directly",[75,130,131,132,135],{},"Full librdkafka configuration, producer transactions, and the high-level consumer, with nothing in between. Use ",[38,133,32],{"href":134},"#php-kafka-lib"," if you want builders, manual commits by default, and Avro encoders.",[57,137,138,143,148],{},[75,139,140],{},[14,141,142],{},"Code already built on Enqueue",[75,144,145],{},[38,146,24],{"href":147},"#enqueue",[75,149,150,151,154],{},"A queue-interop transport that works with or without a framework. Set ",[89,152,153],{},"group.id"," yourself, and replace the default serializer if other services read the topic.",[57,156,157,162,168],{},[75,158,159],{},[14,160,161],{},"Hyperf or Swoole",[75,163,164,167],{},[89,165,166],{},"hyperf\u002Fkafka"," in Hyperf; longlang\u002Fphpkafka in other Swoole apps",[75,169,170,171,173],{},"Pure PHP and coroutine-friendly, without php-rdkafka. ",[89,172,166],{}," is built on longlang\u002Fphpkafka, which has not shipped a new version since October 2023.",[57,175,176,181,184],{},[75,177,178],{},[14,179,180],{},"Cannot install additional PHP extensions",[75,182,183],{},"HTTP through a REST Proxy, or a pure PHP client",[75,185,186,187],{},"Neither needs php-rdkafka, but check their TLS, authentication, and compression dependencies. RoadRunner's Kafka driver is another option if you can run its binary. See ",[38,188,41],{"href":40},[57,190,191,196,203],{},[75,192,193],{},[14,194,195],{},"Avro with Schema Registry",[75,197,198,199,202],{},"Laravel Kafka's Avro serializer, or ",[89,200,201],{},"flix-tech\u002Favro-serde-php"," with other libraries",[75,204,205,206,210],{},"Laravel Kafka has Avro built in; other libraries need a separate Avro serializer and Schema Registry client. See ",[38,207,209],{"href":208},"#avro-and-schema-registry-in-php","Avro and Schema Registry in PHP",".",[46,212,214],{"id":213},"php-extensions-wrappers-and-framework-integrations","PHP extensions, wrappers, and framework integrations",[10,216,217],{},"PHP Kafka libraries sit in three layers:",[219,220,221,228,234],"ul",{},[222,223,224,227],"li",{},[14,225,226],{},"Extension:"," php-rdkafka exposes librdkafka's producer, high-level consumer, and metadata APIs to PHP. Protocol handling, batching, retries, and consumer group membership happen inside librdkafka.",[222,229,230,233],{},[14,231,232],{},"General wrappers:"," php-kafka-lib and Enqueue add builders, message objects, and serializers on top of php-rdkafka, without tying you to a framework.",[222,235,236,239],{},[14,237,238],{},"Framework integrations:"," Laravel Kafka and the Symfony Messenger transports connect php-rdkafka to framework configuration, commands, and handlers.",[10,241,242,243,246],{},"The wrappers call php-rdkafka rather than replace it. Which Kafka features work depends on the librdkafka version the extension loads at runtime, and on limits that php-rdkafka and each wrapper add. ",[89,244,245],{},"php --ri rdkafka"," shows the librdkafka runtime and build versions.",[10,248,249,250,253,254,257],{},"php-rdkafka installs like other PECL extensions: with ",[89,251,252],{},"pecl install rdkafka",", or with PIE, the PHP Foundation's newer extension installer, as ",[89,255,256],{},"rdkafka\u002Frdkafka",". Building from source requires librdkafka and its development headers.",[10,259,260,261,210],{},"Docker images usually install the extension in the Dockerfile, and Linux distributions package it for their PHP builds. Shared and managed hosting often allows only preinstalled extensions; see the ",[38,262,263],{"href":40},"options without php-rdkafka",[10,265,266,267,270,271,274],{},"Composer checks the extension version. Laravel Kafka 2.13.0 requires ",[89,268,269],{},"ext-rdkafka"," ",[89,272,273],{},"^6.0",", and Enqueue 0.10.27 and php-kafka-lib 2.0.2 accept versions 4 to 6, so none of them installs next to php-rdkafka 7.0.0alpha1.",[10,276,277,278,280],{},"koco\u002Fmessenger-kafka only suggests ",[89,279,269],{},", so Composer does not check it, but its native Kafka transport still needs the extension at runtime.",[10,282,283,284,287],{},"PECL also lists ",[89,285,286],{},"simple_kafka_client",", a separate extension that binds librdkafka as well, so it does not avoid native code. Its last PECL release is 0.1.4, from 4 Aug 2021.",[46,289,291],{"id":290},"kafka-php-clients-compared","Kafka PHP clients compared",[10,293,294,297],{},[14,295,296],{},"Capabilities verified against each release's source and documentation:"," 16 Oct 2026",[51,299,300,343],{},[54,301,302],{},[57,303,304,307,315,322,329,336],{},[60,305,306],{},"Area",[60,308,309],{},[38,310,314],{"href":311,"rel":312},"https:\u002F\u002Fgithub.com\u002Fphp-rdkafka\u002Fphp-rdkafka\u002Ftree\u002F6.0.5",[313],"nofollow","php-rdkafka 6.0.5",[60,316,317],{},[38,318,321],{"href":319,"rel":320},"https:\u002F\u002Fgithub.com\u002Fjobcloud\u002Fphp-kafka-lib\u002Ftree\u002Fv2.0.2",[313],"php-kafka-lib 2.0.2",[60,323,324],{},[38,325,328],{"href":326,"rel":327},"https:\u002F\u002Fgithub.com\u002Fphp-enqueue\u002Frdkafka\u002Ftree\u002F0.10.27",[313],"Enqueue rdkafka 0.10.27",[60,330,331],{},[38,332,335],{"href":333,"rel":334},"https:\u002F\u002Fgithub.com\u002Fmateusjunges\u002Flaravel-kafka\u002Ftree\u002Fv2.13.0",[313],"Laravel Kafka 2.13.0",[60,337,338],{},[38,339,342],{"href":340,"rel":341},"https:\u002F\u002Fgithub.com\u002FKonstantinCodes\u002Fmessenger-kafka\u002Ftree\u002Fv0.19",[313],"koco\u002Fmessenger-kafka 0.19",[70,344,345,367,404,443,467,493,511,538],{},[57,346,347,352,355,358,361,364],{},[75,348,349],{},[14,350,351],{},"Requirements",[75,353,354],{},"PHP 7.0+, librdkafka",[75,356,357],{},"PHP 8.0+, ext-rdkafka 4–6",[75,359,360],{},"PHP 8.1+, ext-rdkafka 4–6",[75,362,363],{},"PHP 8.2+, Laravel 12–13, ext-rdkafka 6",[75,365,366],{},"PHP 7.4+, Symfony ^5.4 \u002F ^6.4 \u002F ^7.4 \u002F ^8.1",[57,368,369,374,381,386,393,399],{},[75,370,371],{},[14,372,373],{},"Sending",[75,375,376,377,380],{},"You call ",[89,378,379],{},"flush()","; errors via your callback",[75,382,376,383,385],{},[89,384,379],{},"; failed deliveries throw",[75,387,388,389,392],{},"Flushed at ",[89,390,391],{},"close()"," or shutdown; errors via your callback",[75,394,395,398],{},[89,396,397],{},"send()"," flushes; errors via your callback",[75,400,401,403],{},[89,402,397],{}," flushes; delivery errors not reported",[57,405,406,411,418,424,433,436],{},[75,407,408],{},[14,409,410],{},"Default commits",[75,412,413,414,417],{},"Auto-commit of every record ",[89,415,416],{},"consume()"," returns",[75,419,420,421],{},"None; you call ",[89,422,423],{},"commit()",[75,425,426,427,430,431,417],{},"On ",[89,428,429],{},"acknowledge()","; librdkafka also auto-commits every record ",[89,432,416],{},[75,434,435],{},"Every handled record, failed ones too",[75,437,426,438,430,441,417],{},[89,439,440],{},"ack()",[89,442,416],{},[57,444,445,450,453,455,461,464],{},[75,446,447],{},[14,448,449],{},"Failed records",[75,451,452],{},"Your code",[75,454,452],{},[75,456,457,460],{},[89,458,459],{},"reject($message, true)"," commits, then republishes to the topic",[75,462,463],{},"Retries, dead-letter topic, or stop",[75,465,466],{},"Messenger retries produce copies to the topic",[57,468,469,474,481,484,487,490],{},[75,470,471],{},[14,472,473],{},"Cooperative and KIP-848 groups",[75,475,476,477,480],{},"Yes; use ",[89,478,479],{},"incrementalAssign()"," in callbacks",[75,482,483],{},"Yes, without the bundled callback",[75,485,486],{},"Yes",[75,488,489],{},"Yes, without assignment callbacks",[75,491,492],{},"No",[57,494,495,500,503,505,507,509],{},[75,496,497],{},[14,498,499],{},"Transactions",[75,501,502],{},"Producer only",[75,504,502],{},[75,506,492],{},[75,508,502],{},[75,510,492],{},[57,512,513,517,520,525,528,531],{},[75,514,515],{},[14,516,195],{},[75,518,519],{},"External serializer",[75,521,522,523],{},"With ",[89,524,201],{},[75,526,527],{},"Custom serializer",[75,529,530],{},"Built in",[75,532,533,534,537],{},"Custom serializer; ",[89,535,536],{},"koco\u002Favro-regy"," needs Symfony ^5.4 \u002F ^6.0",[57,539,540,545,548,551,554,557],{},[75,541,542],{},[14,543,544],{},"Latest release",[75,546,547],{},"6.0.5 (4 Nov 2024); 7.0.0alpha1 (7 May 2026)",[75,549,550],{},"v2.0.2 (15 Jun 2026)",[75,552,553],{},"0.10.27 (4 Apr 2026)",[75,555,556],{},"v2.13.0 (7 Oct 2026)",[75,558,559],{},"v0.19 (1 Oct 2026)",[10,561,562,563],{},"All five run on librdkafka, so SASL, TLS, and compression are librdkafka properties in each, and their default key partitioner differs from Java's; see ",[38,564,566],{"href":565},"#do-php-kafka-clients-partition-keys-the-same-way-as-java","Do PHP Kafka clients partition keys the same way as Java?",[10,568,569,570,210],{},"Cooperative rebalancing moves only the partitions that change owner instead of pausing every consumer. KIP-848, generally available since Kafka 4.0, moves partition assignment to the brokers; it needs librdkafka 2.12.0+ and ",[89,571,572],{},"group.protocol=consumer",[10,574,575,576,210],{},"In the versions compared here, producer transactions cannot include consumer offsets; php-rdkafka 7.0.0alpha1 adds ",[89,577,578],{},"sendOffsetsToTransaction()",[580,581,16],"h3",{"id":16},[10,583,584,588,589,592,593,596,597,600,601,604],{},[38,585,16],{"href":586,"rel":587},"https:\u002F\u002Fgithub.com\u002Fphp-rdkafka\u002Fphp-rdkafka",[313]," is the PECL extension ",[89,590,591],{},"rdkafka",". Its API follows librdkafka closely: ",[89,594,595],{},"RdKafka\\Conf"," takes librdkafka configuration properties, ",[89,598,599],{},"RdKafka\\Producer"," produces, and ",[89,602,603],{},"RdKafka\\KafkaConsumer"," is the high-level, group-aware consumer.",[10,606,607],{},[14,608,609],{},"Capabilities and limitations",[219,611,612,635,650,668,687,693,716,740,764,770,790],{},[222,613,614,270,617,620,621,624,625,628,629,631,632,634],{},[14,615,616],{},"Producing:",[89,618,619],{},"producev()"," only queues a record; delivery reports reach your ",[89,622,623],{},"setDrMsgCb()"," callback during ",[89,626,627],{},"poll()"," or ",[89,630,379],{},". Call ",[89,633,379],{}," before the script ends, because the destructor purges records still queued or in flight.",[222,636,637,640,641,21,643,645,646,649],{},[14,638,639],{},"Default commits:"," librdkafka commits in two steps. With ",[89,642,110],{},[89,644,416],{}," marks each returned record's offset; with ",[89,647,648],{},"enable.auto.commit",", marked offsets are committed every 5 seconds, so a record can be committed before its processing finishes.",[222,651,652,655,656,111,658,660,661,628,664,667],{},[14,653,654],{},"Manual commits:"," Set ",[89,657,648],{},[89,659,114],{}," and call ",[89,662,663],{},"commit($message)",[89,665,666],{},"commitAsync($message)"," after each record succeeds.",[222,669,670,673,674,111,676,678,679,682,683,686],{},[14,671,672],{},"Automatic commits after success:"," Keep auto-commit, set ",[89,675,110],{},[89,677,114],{},", and call ",[89,680,681],{},"offsetStore()"," after each record succeeds. Reuse one ",[89,684,685],{},"newTopic()"," handle per topic; 6.0.5 does not release them.",[222,688,689,692],{},[14,690,691],{},"Commit order:"," With either approach, do not store or commit past an earlier record in the same partition that has not succeeded.",[222,694,695,698,699,701,702,705,706,708,709,712,713,210],{},[14,696,697],{},"Consumer groups:"," KIP-848 works with librdkafka 2.12.0+ and Kafka 4.0+ once you set ",[89,700,572],{},"; the default is ",[89,703,704],{},"classic",". A rebalance callback must then use ",[89,707,479],{}," and ",[89,710,711],{},"incrementalUnassign()",", as with ",[89,714,715],{},"cooperative-sticky",[222,717,718,270,721,724,725,21,728,21,731,29,734,737,738,210],{},[14,719,720],{},"Transactions:",[89,722,723],{},"Producer"," supports ",[89,726,727],{},"initTransactions()",[89,729,730],{},"beginTransaction()",[89,732,733],{},"commitTransaction()",[89,735,736],{},"abortTransaction()",". 6.0.5 cannot add consumer offsets to a transaction; 7.0.0alpha1 adds ",[89,739,578],{},[222,741,742,270,745,748,749,751,752,755,756,759,760,763],{},[14,743,744],{},"OAUTHBEARER:",[89,746,747],{},"setOauthbearerTokenRefreshCb()"," registers a token callback, but in 6.0.5 only ",[89,750,723],{}," and the low-level ",[89,753,754],{},"Consumer"," have ",[89,757,758],{},"oauthbearerSetToken()",". ",[89,761,762],{},"KafkaConsumer"," gains it in 7.0.0alpha1.",[222,765,766,769],{},[14,767,768],{},"Admin operations:"," Neither 6.0.5 nor 7.0.0alpha1 has an Admin API, so creating topics or changing their configuration needs another tool.",[222,771,772,775,776,779,780,783,784,786,787,210],{},[14,773,774],{},"7.0 changes:"," 7.0.0alpha1 requires PHP 8.1 and librdkafka 1.5.3 or later. ",[89,777,778],{},"KafkaConsumer::consume()"," now returns ",[89,781,782],{},"null"," on timeout, so check for ",[89,785,782],{}," before reading ",[89,788,789],{},"$message->err",[222,791,792,795,796,799,800,802],{},[14,793,794],{},"Maintenance:"," The repository moved from ",[89,797,798],{},"arnaud-lb\u002Fphp-rdkafka"," to the php-rdkafka organization in April 2026 and had commits through September 2026. The extension is also published for PIE as ",[89,801,256],{},", with 8,010 installs through PIE in 30 days.",[10,804,805,808],{},[14,806,807],{},"When to choose:"," Choose php-rdkafka directly for plain PHP services and CLI workers that need full control over librdkafka settings, commits, and transactions, or as the base of your own thin wrapper.",[580,810,32],{"id":32},[10,812,813,817],{},[38,814,32],{"href":815,"rel":816},"https:\u002F\u002Fgithub.com\u002Fjobcloud\u002Fphp-kafka-lib",[313]," from Jobcloud wraps php-rdkafka in builders and message objects and adds JSON and Avro encoders. It suits plain PHP applications that want safer consumer defaults than php-rdkafka's.",[10,819,820],{},[14,821,609],{},[219,823,824,835,850,868,892,908,915,932],{},[222,825,826,270,828,831,832,834],{},[14,827,616],{},[89,829,830],{},"produce()"," queues a record and polls with a zero timeout, but blocks while librdkafka's queue is full. Call ",[89,833,379],{}," before the script ends and check its return code.",[222,836,837,840,841,844,845,628,847,849],{},[14,838,839],{},"Delivery errors:"," The default delivery report callback throws ",[89,842,843],{},"KafkaProducerException"," from ",[89,846,627],{},[89,848,379],{}," when a record fails.",[222,851,852,855,856,859,860,863,864,867],{},[14,853,854],{},"Producer settings:"," The builder hardcodes ",[89,857,858],{},"socket.timeout.ms",", librdkafka's network request timeout, to 50 ms, so test with realistic latency. It sets your ",[89,861,862],{},"queue.buffering.max.ms"," to 1 ms, or drops it when ",[89,865,866],{},"pcntl_sigprocmask()"," exists so librdkafka's default applies.",[222,869,870,873,874,877,878,631,881,883,884,887,888,891],{},[14,871,872],{},"Consumer defaults:"," Auto-commit and automatic offset storing are off, and ",[89,875,876],{},"auto.offset.reset"," is ",[89,879,880],{},"earliest",[89,882,423],{}," with the message after processing. Without ",[89,885,886],{},"withConsumerGroup()",", the group ID is ",[89,889,890],{},"default",", shared by every consumer that does not set one.",[222,893,894,896,897,900,901,904,905,907],{},[14,895,697],{}," No rebalance callback is registered unless you pass one. The bundled ",[89,898,899],{},"KafkaConsumerRebalanceCallback"," uses eager ",[89,902,903],{},"assign()",", so do not use it with ",[89,906,715],{}," or KIP-848. A low-level consumer type covers manual partition assignment.",[222,909,910,270,912,914],{},[14,911,720],{},[89,913,730],{}," initializes transactions on first use. Transaction errors are mapped to retry, abort, and fatal exception classes.",[222,916,917,270,920,708,923,926,927,929,930,210],{},[14,918,919],{},"Avro:",[89,921,922],{},"AvroEncoder",[89,924,925],{},"AvroDecoder"," need ",[89,928,201],{},"; see ",[38,931,209],{"href":208},[222,933,934,936],{},[14,935,794],{}," v2.0.1 and v2.0.2 shipped in March and June 2026. The 16 Oct 2026 snapshot found no commits in the preceding 90 days.",[10,938,939,941],{},[14,940,807],{}," Choose php-kafka-lib for plain PHP services that want manual commits by default and an Avro encoder, without adopting a framework.",[580,943,24],{"id":944},"enqueue",[10,946,947,951,952,955,956,959,960,210],{},[38,948,24],{"href":949,"rel":950},"https:\u002F\u002Fgithub.com\u002Fphp-enqueue\u002Fenqueue-dev",[313]," is a messaging library built on the queue-interop interfaces. Its Kafka transport, ",[89,953,954],{},"enqueue\u002Frdkafka",", works on its own, as a Laravel queue connection through ",[89,957,958],{},"enqueue\u002Flaravel-queue",", and as a Symfony Messenger transport through ",[89,961,962],{},"sroze\u002Fmessenger-enqueue-transport",[10,964,965],{},[14,966,609],{},[219,968,969,986,1002,1016,1025,1040,1051,1066],{},[222,970,971,974,975,977,978,981,982,985],{},[14,972,973],{},"Default group ID:"," Without a ",[89,976,153],{}," under ",[89,979,980],{},"global",", the connection factory generates one with ",[89,983,984],{},"uniqid()",". A restarted consumer then joins a new group and does not resume from committed offsets.",[222,987,988,991,992,21,995,29,998,1001],{},[14,989,990],{},"Message format:"," The default serializer stores a JSON object with ",[89,993,994],{},"body",[89,996,997],{},"properties",[89,999,1000],{},"headers"," as the record value. Consumers outside Enqueue see that envelope, not your payload, so use a custom serializer for shared topics.",[222,1003,1004,270,1006,1008,1009,1011,1012,1015],{},[14,1005,616],{},[89,1007,397],{}," queues a record and polls without flushing. ",[89,1010,391],{}," and a shutdown function flush, waiting without limit unless you set ",[89,1013,1014],{},"shutdown_timeout",", and both ignore the result.",[222,1017,1018,1020,1021,1024],{},[14,1019,839],{}," To confirm delivery, flush explicitly, check the return code, and register a ",[89,1022,1023],{},"dr_msg_cb"," delivery report callback.",[222,1026,1027,270,1030,1032,1033,111,1035,977,1037,1039],{},[14,1028,1029],{},"Commits:",[89,1031,429],{}," commits, asynchronously by default. librdkafka's defaults can commit a returned record before you acknowledge it, so set ",[89,1034,110],{},[89,1036,114],{},[89,1038,980],{}," and acknowledge after success.",[222,1041,1042,270,1045,1047,1048,210],{},[14,1043,1044],{},"Failures:",[89,1046,459],{}," acknowledges the record, then sends a copy to the same topic. The two steps are not atomic, so requeueing can lose or duplicate records. The producer rejects delivery delays with a ",[89,1049,1050],{},"LogicException",[222,1052,1053,1056,1057,21,1060,29,1062,1065],{},[14,1054,1055],{},"Coverage:"," There is no transaction API. A rebalance callback, delivery report callback, and partitioner can be set through the ",[89,1058,1059],{},"rebalance_cb",[89,1061,1023],{},[89,1063,1064],{},"partitioner"," options.",[222,1067,1068,1070,1071,1074,1075,1079],{},[14,1069,794],{}," 0.10.27 was released on 4 Apr 2026 from the ",[89,1072,1073],{},"enqueue-dev"," monorepo; see the ",[38,1076,1078],{"href":1077},"#github-repository-metrics","repository metrics"," for its backlog.",[10,1081,1082,1084],{},[14,1083,807],{}," Choose Enqueue if your application already uses it, or if you need one queue-interop API across several brokers. For Kafka-only code, the other libraries map more directly onto Kafka's model.",[46,1086,1088],{"id":1087},"kafka-in-laravel-and-symfony","Kafka in Laravel and Symfony",[580,1090,1092],{"id":1091},"laravel-kafka-producers-and-consumers","Laravel Kafka: producers and consumers",[10,1094,1095,1099],{},[38,1096,20],{"href":1097,"rel":1098},"https:\u002F\u002Fgithub.com\u002Fmateusjunges\u002Flaravel-kafka",[313]," is the most installed library in this guide, with 184,251 Packagist installs in 30 days. Version 2.13.0, released on 7 Oct 2026, supports PHP 8.2 to 8.5 and Laravel 12 and 13, and requires php-rdkafka 6.x.",[10,1101,1102],{},[14,1103,1104],{},"Producing",[219,1106,1107,1115,1127,1139,1153],{},[222,1108,1109,270,1112,1114],{},[14,1110,1111],{},"Synchronous sends:",[89,1113,397],{}," builds a new php-rdkafka producer for each call and flushes it with a 1-second timeout, making up to 10 attempts by default.",[222,1116,1117,1119,1120,1122,1123,1126],{},[14,1118,839],{}," A successful ",[89,1121,379],{}," only means the local queue is empty; records that failed delivery are removed from it too. Register a ",[89,1124,1125],{},"withDrMsgCb()"," callback to catch per-record errors.",[222,1128,1129,270,1132,1135,1136,1138],{},[14,1130,1131],{},"Asynchronous sends:",[89,1133,1134],{},"Kafka::asyncPublish()"," reuses one producer, and its ",[89,1137,397],{}," returns before delivery. The producer is flushed when it is destroyed, at the end of the request under PHP-FPM.",[222,1140,1141,1144,1145,1148,1149,1152],{},[14,1142,1143],{},"Headers:"," Each record gets a ",[89,1146,1147],{},"laravel-kafka::message-id"," header with a UUID; the header name comes from the ",[89,1150,1151],{},"kafka.message_id_key"," setting.",[222,1154,1155,270,1157,1160],{},[14,1156,720],{},[89,1158,1159],{},"transactional()"," producers support begin, commit, and abort. As with php-rdkafka 6.x, consumer offsets cannot be committed inside the transaction.",[10,1162,1163],{},[14,1164,1165],{},"Consuming",[219,1167,1168,1180,1185,1202,1215,1232,1245,1261,1271],{},[222,1169,1170,1173,1174,1177,1178,210],{},[14,1171,1172],{},"Running:"," Start consumers with ",[89,1175,1176],{},"php artisan kafka:consume",", or build one in code and call ",[89,1179,416],{},[222,1181,1182,1184],{},[14,1183,639],{}," librdkafka's auto-commit stays on, so a record can be committed before its handler finishes. The consumer also commits each handled record synchronously, success or failure, so failed records are not consumed again.",[222,1186,1187,270,1190,1193,1194,1197,1198,1201],{},[14,1188,1189],{},"Batch and manual commits:",[89,1191,1192],{},"withCommitBatchSize()"," runs the library's own commit every N records, while librdkafka's auto-commit keeps running. ",[89,1195,1196],{},"withManualCommit()"," turns both off; call ",[89,1199,1200],{},"$consumer->commit($message)"," in the handler.",[222,1203,1204,270,1207,1210,1211,1214],{},[14,1205,1206],{},"Retries:",[89,1208,1209],{},"retryFailedMessages()"," reruns the handler in process; exhausted retries still follow the dead-letter, stop, or skip behavior. Keep each record's total time, including all attempts and backoff, below ",[89,1212,1213],{},"max.poll.interval.ms"," (five minutes by default).",[222,1216,1217,270,1220,1223,1224,1227,1228,1231],{},[14,1218,1219],{},"Dead-letter topic:",[89,1221,1222],{},"withDlq()"," sends a failed record to ",[89,1225,1226],{},"\u003Ctopic>-dlq"," with ",[89,1229,1230],{},"kafka_throwable_*"," headers, then commits the original, even with manual commits. It ignores the result of its 12-second flush, so a failed DLQ write can still lose the record.",[222,1233,1234,1237,1238,1240,1241,1244],{},[14,1235,1236],{},"Stopping on failure:"," Without a dead-letter topic, ",[89,1239,91],{}," closes the consumer without committing the failed record and throws ",[89,1242,1243],{},"ConsumerException",". Run it under a process manager that restarts it with the same group ID to read the record again.",[222,1246,1247,1250,1251,21,1254,29,1257,1260],{},[14,1248,1249],{},"Shutdown:"," With pcntl loaded, ",[89,1252,1253],{},"SIGTERM",[89,1255,1256],{},"SIGINT",[89,1258,1259],{},"SIGQUIT"," stop the loop after the current record. php-rdkafka closes the consumer, leaving the group, when the consumer object is destroyed.",[222,1262,1263,1266,1267,1270],{},[14,1264,1265],{},"Queueable handlers:"," A handler that implements ",[89,1268,1269],{},"ShouldQueue"," dispatches one Laravel queue job per record. The record counts as handled once the job is dispatched, so failures inside the job are handled by Laravel's queue, not by the Kafka consumer.",[222,1272,1273,1275,1276,708,1279,1282,1283,1285,1286,1288],{},[14,1274,697],{}," No rebalance callback is registered by default. ",[89,1277,1278],{},"withPartitionAssignmentCallback()",[89,1280,1281],{},"assignPartitionsWithOffsets()"," register one that uses eager ",[89,1284,903],{},", so do not combine them with ",[89,1287,715],{}," or KIP-848.",[10,1290,1291,1292,1295,1296,210],{},"Laravel Kafka produces and consumes records; it does not register a Laravel queue connection, so ",[89,1293,1294],{},"dispatch()"," does not send jobs to Kafka. Using Kafka as a queue backend needs a separate queue driver, such as ",[89,1297,958],{},[10,1299,1300,1301,1304,1305,1308],{},"A smaller alternative, ",[89,1302,1303],{},"ensi\u002Flaravel-phprdkafka",", defines php-rdkafka producers and consumers in ",[89,1306,1307],{},"config\u002Fkafka.php","; companion packages add higher-level producers and consumers. Version 0.4.6 (23 Jan 2026) supports Laravel 9 to 12, with 2,667 installs in 30 days.",[580,1310,1312],{"id":1311},"symfony-messenger-kafka-koco-vs-enqueue","Symfony Messenger Kafka: koco vs Enqueue",[10,1314,1315,1316,210],{},"Symfony Messenger has no built-in Kafka transport. Symfony's documentation points to Enqueue's transport for brokers such as Kafka; the more direct option is ",[89,1317,28],{},[10,1319,1320,1322,1323,628,1326,1329,1330,708,1333,1336],{},[14,1321,28],{}," v0.19 supports Symfony ^5.4 \u002F ^6.4 \u002F ^7.4 \u002F ^8.1 on PHP 7.4 or later (8.4 for Symfony 8.1). Each transport has one DSN (",[89,1324,1325],{},"kafka:\u002F\u002F",[89,1327,1328],{},"kafka+ssl:\u002F\u002F","), one topic, and ",[89,1331,1332],{},"kafka_conf",[89,1334,1335],{},"topic_conf"," maps for librdkafka.",[219,1338,1339,1353,1367,1384,1400,1408,1421,1432],{},[222,1340,1341,1344,1345,21,1348,29,1350,1352],{},[14,1342,1343],{},"Serializer:"," Messenger's default serializer stores a serialized PHP envelope in the record value. For topics shared with other services, write a serializer that maps the ",[89,1346,1347],{},"key",[89,1349,1000],{},[89,1351,994],{}," fields, as in the README's example.",[222,1354,1355,270,1358,1360,1361,1364,1365,210],{},[14,1356,1357],{},"TLS:",[89,1359,1328],{}," only selects the transport. It does not set ",[89,1362,1363],{},"security.protocol",", so set that in ",[89,1366,1332],{},[222,1368,1369,1372,1373,1375,1376,1379,1380,1383],{},[14,1370,1371],{},"Sending:"," Each ",[89,1374,397],{}," produces one record and flushes, with a 10-second timeout and no extra attempts unless ",[89,1377,1378],{},"flushRetries"," is set. A flush that does not complete throws ",[89,1381,1382],{},"TransportException","; delivery reports are not checked.",[222,1385,1386,270,1389,1391,1392,1395,1396,1399],{},[14,1387,1388],{},"Receiving:",[89,1390,440],{}," commits the record, synchronously unless ",[89,1393,1394],{},"commitAsync"," is set. Set ",[89,1397,1398],{},"enable.auto.offset.store: 'false'",", as the README recommends; otherwise librdkafka can auto-commit a record before its handler finishes, even if it then fails.",[222,1401,1402,270,1404,1407],{},[14,1403,1206],{},[89,1405,1406],{},"reject()"," does nothing. Messenger retries a failed message by producing a copy to the same topic, and koco ignores the retry delay.",[222,1409,1410,1413,1414,1416,1417,1420],{},[14,1411,1412],{},"Final failures:"," The next ",[89,1415,440],{}," on the partition commits past the failed record. Configure Messenger's ",[89,1418,1419],{},"failure_transport"," to keep messages that exhaust their retries; otherwise later commits skip them. Resending and committing are not atomic.",[222,1422,1423,1425,1426,1428,1429,1431],{},[14,1424,697],{}," The transport always registers a rebalance callback that uses eager ",[89,1427,903],{},", so ",[89,1430,715],{}," and KIP-848 do not work.",[222,1433,1434,1437,1438,1441],{},[14,1435,1436],{},"REST Proxy:"," v0.19 also includes a send-only transport (",[89,1439,1440],{},"kafka+rest:\u002F\u002F",") that posts records to a REST Proxy; receiving through it is not implemented.",[10,1443,1444,1449,1450,1452],{},[14,1445,1446,1447],{},"Enqueue through ",[89,1448,962],{}," 1.0.0 (8 Feb 2026) adapts any Enqueue transport, including ",[89,1451,954],{},", to Messenger. It requires PHP ^8.1 and Symfony Messenger ^6.4 \u002F ^7.0 \u002F ^8.0.",[10,1454,1455,1456,1458,1459,111,1462,1465],{},"Enqueue's behavior applies: set ",[89,1457,153],{}," and a serializer, and turn off automatic offset storing. Its Kafka producer rejects any delivery delay, but this transport skips a zero delay, so set Messenger's retry ",[89,1460,1461],{},"delay",[89,1463,1464],{},"0","; the one-second default throws.",[10,1467,1468,1469,1472,1473,1476],{},"Two smaller packages also exist: ",[89,1470,1471],{},"exoticca\u002Fkafka-transport",", another Messenger transport with 1,864 installs in 30 days, and ",[89,1474,1475],{},"simpod\u002Fkafka-bundle",", which integrates php-rdkafka with Symfony without Messenger, with 3,651.",[46,1478,209],{"id":1479},"avro-and-schema-registry-in-php",[10,1481,1482],{},"php-rdkafka sends and receives bytes. Avro with Confluent Schema Registry comes from separate packages, and the libraries in this guide use them differently:",[219,1484,1485,1494,1507,1515,1521],{},[222,1486,1487,1489,1490,1493],{},[14,1488,201],{}," 3.0.0 (25 Dec 2024, PHP ^8.1) serializes and deserializes Avro records in Confluent's wire format, using ",[89,1491,1492],{},"flix-tech\u002Fconfluent-schema-registry-api"," 8.1.0 for schemas. php-kafka-lib's Avro encoder and decoder build on it.",[222,1495,1496,1498,1499,1502,1503,1506],{},[14,1497,20],{}," uses forks of both, ",[89,1500,1501],{},"mateusjunges\u002Favro-serde-php"," (v3.1.0, 8 Oct 2026) and ",[89,1504,1505],{},"mateusjunges\u002Fconfluent-schema-registry-api",". It encodes and decodes only keys and values whose topic has a schema mapping; others pass through unchanged.",[222,1508,1509,1511,1512,1514],{},[14,1510,536],{}," v1.2.0 (October 2022) connects the koco transport to Schema Registry but requires Symfony ^5.4 or ^6.0 and serde ^2.0. On Symfony 7 or 8, call ",[89,1513,201],{}," from a custom serializer instead.",[222,1516,1517,1520],{},[14,1518,1519],{},"jobcloud\u002Fphp-kafka-schema-registry-client"," v3.0.0 (4 Feb 2026, PHP ^8.4) registers and looks up schemas and checks compatibility. It does not serialize Avro records, so it cannot replace the FlixTech serde that php-kafka-lib uses.",[222,1522,1523,1525],{},[14,1524,24],{}," has no Avro support; use a custom serializer.",[10,1527,1528,1529,1532],{},"Use a caching registry client, such as FlixTech's ",[89,1530,1531],{},"CachedRegistry","; without one, every record you serialize or deserialize makes an HTTP request to Schema Registry.",[10,1534,1535,1536,1541],{},"None of these libraries ships Protobuf or JSON Schema serializers for Schema Registry. If you exchange those formats, follow Confluent's ",[38,1537,1540],{"href":1538,"rel":1539},"https:\u002F\u002Fdocs.confluent.io\u002Fplatform\u002Fcurrent\u002Fschema-registry\u002Ffundamentals\u002Fserdes-develop\u002Findex.html#wire-format",[313],"wire format"," and test round trips in both directions with your existing producers and consumers.",[46,1543,1545],{"id":1544},"php-fpm-producers-and-long-running-consumers","PHP-FPM producers and long-running consumers",[10,1547,1548],{},"PHP-FPM (FastCGI Process Manager) manages the worker processes that handle PHP web requests. Flush producers before requests end, and run consumers as separate CLI workers.",[10,1550,1551],{},[14,1552,1553],{},"Producing from web requests",[219,1555,1556,1565,1579,1585,1591],{},[222,1557,1558,1561,1562,1564],{},[14,1559,1560],{},"A producer per request:"," Under PHP-FPM, objects do not survive the request, so each producing request creates a new librdkafka producer, with new connections, TLS and SASL handshakes, and a metadata fetch. Laravel Kafka's ",[89,1563,397],{}," does this on every call.",[222,1566,1567,1570,1571,1573,1574,1578],{},[14,1568,1569],{},"Flush before the request ends:"," php-rdkafka's producer destructor purges what is left, so without ",[89,1572,379],{},", queued records can be discarded and in-flight delivery can remain unconfirmed. The ",[38,1575,1577],{"href":1576},"#kafka-php-clients-compared","comparison table"," shows which libraries flush for you.",[222,1580,1581,1584],{},[14,1582,1583],{},"Flushing blocks the response:"," Choose a timeout, check the return value, and use delivery reports for per-record failures.",[222,1586,1587,1590],{},[14,1588,1589],{},"Outbox:"," If a response must not wait for Kafka, write the event to an outbox table in the same database transaction as the business change, and publish it from a long-running worker.",[222,1592,1593,1596,1597,1599],{},[14,1594,1595],{},"Worker-mode runtimes:"," RoadRunner, Swoole or Hyperf, and FrankenPHP's worker mode can reuse a producer retained for the worker's lifetime; Laravel Octane runs on RoadRunner, Swoole, and FrankenPHP. Keep calling ",[89,1598,627],{},", and flush when the worker stops.",[10,1601,1602],{},[14,1603,1604],{},"Running consumers",[219,1606,1607,1620,1630,1642,1654,1659],{},[222,1608,1609,1612,1613,1615,1616,1619],{},[14,1610,1611],{},"Process model:"," Run consumers as CLI processes under Supervisor, systemd, or Kubernetes, not inside PHP-FPM requests. ",[89,1614,1176],{}," and Symfony's ",[89,1617,1618],{},"messenger:consume"," are such processes.",[222,1621,1622,1624,1625,1627,1628,210],{},[14,1623,1029],{}," Commit only after processing succeeds. Defaults differ: php-kafka-lib waits for your ",[89,1626,423],{},", Laravel Kafka commits failed records, and php-rdkafka, Enqueue, and koco auto-store offsets; see the ",[38,1629,1577],{"href":1576},[222,1631,1632,1635,1636,1638,1639,1641],{},[14,1633,1634],{},"Poll interval:"," Keep the time between ",[89,1637,416],{}," calls, including processing, retries, and commits, below ",[89,1640,1213],{}," (five minutes by default). Exceeding it can trigger a rebalance and make commits fail.",[222,1643,1644,1647,1648,1650,1651,1653],{},[14,1645,1646],{},"Signals:"," Laravel Kafka and ",[89,1649,1618],{}," register ",[89,1652,1253],{}," handlers when pcntl is loaded and stop after the current record. With php-rdkafka or php-kafka-lib, register your own handler that sets a stop flag.",[222,1655,1656,1658],{},[14,1657,1249],{}," After the last record, close the consumer so it leaves the group and, with auto-commit on, commits stored offsets. Give the process manager a grace period that covers the current record, commits, and close.",[222,1660,1661,1664,1665,628,1668,1671,1672,21,1675,29,1678,1681],{},[14,1662,1663],{},"Restarts:"," Long-running PHP processes accumulate memory and stale state. Restart them periodically with Laravel Kafka's ",[89,1666,1667],{},"withMaxMessages()",[89,1669,1670],{},"withMaxTime()",", or Messenger's ",[89,1673,1674],{},"--limit",[89,1676,1677],{},"--time-limit",[89,1679,1680],{},"--memory-limit",", and let the process manager start a new one.",[46,1683,41],{"id":1684},"can-you-use-kafka-without-php-rdkafka",[10,1686,1687],{},"Two different needs lead here. Some teams want to avoid php-rdkafka itself, for example to skip building librdkafka or to run inside Swoole coroutines. Others deploy to hosts where they cannot install additional extensions.",[10,1689,1690],{},"Pure PHP clients and HTTP avoid php-rdkafka, but check what their authentication, TLS, and compression support depends on. RoadRunner needs its own binary, and FFI needs librdkafka.",[219,1692,1693,1710,1728,1734,1745,1755,1765],{},[222,1694,1695,1702,1703,1709],{},[14,1696,1697],{},[38,1698,1701],{"href":1699,"rel":1700},"https:\u002F\u002Fgithub.com\u002Fswoole\u002Fphpkafka",[313],"longlang\u002Fphpkafka"," implements Kafka in PHP for PHP-FPM and Swoole, with a group consumer, SSL, and SASL\u002FPLAIN, but no SCRAM, transactions, or KIP-848. Its latest version points to an October 2023 commit; Hyperf's ",[38,1704,1707],{"href":1705,"rel":1706},"https:\u002F\u002Fgithub.com\u002Fhyperf\u002Fkafka",[313],[89,1708,166],{}," builds on it.",[222,1711,1712,1719,1720,1727],{},[14,1713,1714],{},[38,1715,1718],{"href":1716,"rel":1717},"https:\u002F\u002Fgithub.com\u002Froadrunner-server\u002Fkafka",[313],"RoadRunner's Kafka driver"," (v6.0.0, 8 Oct 2026) runs franz-go in RoadRunner's Go process. PHP workers receive records as jobs and push new ones through ",[38,1721,1724],{"href":1722,"rel":1723},"https:\u002F\u002Fgithub.com\u002Froadrunner-php\u002Fjobs",[313],[89,1725,1726],{},"spiral\u002Froadrunner-jobs",". It supports SASL\u002FPLAIN, SCRAM, and AWS MSK IAM, and needs the RoadRunner binary.",[222,1729,1730,1733],{},[14,1731,1732],{},"RoadRunner acknowledgements"," mark a record for periodic offset commits. A negative acknowledgement does not hold the partition back, so acknowledging a later record commits past it; requeued jobs are retried in memory only.",[222,1735,1736,1739,1740,1744],{},[14,1737,1738],{},"HTTP through a REST Proxy"," needs only an HTTP client: producing is one POST per batch, while consumer instances live on the proxy. See ",[38,1741,1743],{"href":1742},"\u002Fblog\u002Fkafka-rest-proxy","Kafka REST Proxy","; koco\u002Fmessenger-kafka 0.19 also has a send-only REST Proxy transport.",[222,1746,1747,1754],{},[14,1748,1749],{},[38,1750,1753],{"href":1751,"rel":1752},"https:\u002F\u002Fgithub.com\u002Flisachenko\u002Fkafka-client",[313],"lisachenko\u002Fkafka-client"," 4.3.1 is a pure PHP client for PHP 8.4+ implementing the Kafka 4.3.1 protocol, including KIP-848 groups, transactions, and KIP-932 share consumers for queue-style reading. It supports only SASL\u002FPLAIN and had 10 Packagist installs in 30 days.",[222,1756,1757,1764],{},[14,1758,1759],{},[38,1760,1763],{"href":1761,"rel":1762},"https:\u002F\u002Fgithub.com\u002Fidealo\u002Fphp-rdkafka-ffi",[313],"idealo\u002Fphp-rdkafka-ffi"," called librdkafka through PHP's FFI extension. It still needed librdkafka installed and FFI enabled, and it was archived on 27 Oct 2025.",[222,1766,1767,1774],{},[14,1768,1769],{},[38,1770,1773],{"href":1771,"rel":1772},"https:\u002F\u002Fgithub.com\u002Fweiboad\u002Fkafka-php",[313],"nmred\u002Fkafka-php",", once a common pure PHP client, was archived on 10 Jun 2022, and its last tag dates from 2017. It still had 8,251 installs in 30 days.",[46,1776,1778],{"id":1777},"github-repository-metrics","GitHub repository metrics",[10,1780,1781],{},"The tables below compare the four repositories' GitHub activity, maintenance, and public usage, with Packagist installs as the usage signal. Snapshot: 16 Oct 2026.",[10,1783,1784,1785,1787],{},"php-rdkafka moved from ",[89,1786,798],{}," to the php-rdkafka organization in April 2026 and kept its creation date, stars, and history.",[10,1789,1790,1791,1794,1795,1797],{},"Enqueue's figures come from the ",[89,1792,1793],{},"php-enqueue\u002Fenqueue-dev"," monorepo, of which ",[89,1796,954],{}," is a read-only split, so they cover every Enqueue transport, not only Kafka.",[580,1799,1801],{"id":1800},"project-overview","Project overview",[51,1803,1804,1831],{},[54,1805,1806],{},[57,1807,1808,1810,1815,1820,1826],{},[60,1809],{},[60,1811,1812],{},[38,1813,16],{"href":586,"rel":1814},[313],[60,1816,1817],{},[38,1818,20],{"href":1097,"rel":1819},[313],[60,1821,1822],{},[38,1823,28],{"href":1824,"rel":1825},"https:\u002F\u002Fgithub.com\u002FKonstantinCodes\u002Fmessenger-kafka",[313],[60,1827,1828],{},[38,1829,24],{"href":949,"rel":1830},[313],[70,1832,1833,1850],{},[57,1834,1835,1838,1841,1844,1847],{},[75,1836,1837],{},"Repository created",[75,1839,1840],{},"30 Mar 2015",[75,1842,1843],{},"16 Aug 2021",[75,1845,1846],{},"10 Jun 2019",[75,1848,1849],{},"29 Dec 2016",[57,1851,1852,1855,1858,1860,1862],{},[75,1853,1854],{},"License",[75,1856,1857],{},"MIT",[75,1859,1857],{},[75,1861,1857],{},[75,1863,1857],{},[580,1865,1867],{"id":1866},"activity","Activity",[51,1869,1870,1897],{},[54,1871,1872],{},[57,1873,1874,1877,1882,1887,1892],{},[60,1875,1876],{},"Metric",[60,1878,1879],{},[38,1880,16],{"href":586,"rel":1881},[313],[60,1883,1884],{},[38,1885,20],{"href":1097,"rel":1886},[313],[60,1888,1889],{},[38,1890,28],{"href":1824,"rel":1891},[313],[60,1893,1894],{},[38,1895,24],{"href":949,"rel":1896},[313],[70,1898,1899,1916,1930,1946,1963,1980,1997],{},[57,1900,1901,1904,1907,1910,1913],{},[75,1902,1903],{},"Latest default-branch commit",[75,1905,1906],{},"8 Sep 2026",[75,1908,1909],{},"7 Oct 2026",[75,1911,1912],{},"1 Oct 2026",[75,1914,1915],{},"30 Aug 2026",[57,1917,1918,1921,1924,1926,1928],{},[75,1919,1920],{},"Latest GitHub Release",[75,1922,1923],{},"6.0.5 (4 Nov 2024)",[75,1925,556],{},[75,1927,559],{},[75,1929,553],{},[57,1931,1932,1935,1937,1940,1943],{},[75,1933,1934],{},"GitHub Releases (12 mo)",[75,1936,1464],{},[75,1938,1939],{},"13",[75,1941,1942],{},"1",[75,1944,1945],{},"3",[57,1947,1948,1951,1954,1957,1960],{},[75,1949,1950],{},"Commits",[75,1952,1953],{},"14 (90 d) · 53 (12 mo)",[75,1955,1956],{},"13 (90 d) · 38 (12 mo)",[75,1958,1959],{},"1 (90 d) · 1 (12 mo)",[75,1961,1962],{},"2 (90 d) · 47 (12 mo)",[57,1964,1965,1968,1971,1974,1977],{},[75,1966,1967],{},"Issue flow (90 d)",[75,1969,1970],{},"0 opened · 3 closed",[75,1972,1973],{},"3 opened · 7 closed",[75,1975,1976],{},"0 opened · 0 closed",[75,1978,1979],{},"1 opened · 0 closed",[57,1981,1982,1985,1988,1991,1994],{},[75,1983,1984],{},"PR flow (90 d)",[75,1986,1987],{},"18 opened · 7 merged",[75,1989,1990],{},"11 opened · 11 merged",[75,1992,1993],{},"2 opened · 1 merged",[75,1995,1996],{},"1 opened · 1 merged",[57,1998,1999,2002,2005,2008,2011],{},[75,2000,2001],{},"Activity assessment",[75,2003,2004],{},"🟢 14 commits and 7 merged PRs in the last 90 days.",[75,2006,2007],{},"🟢 13 commits and 11 merged PRs in the last 90 days.",[75,2009,2010],{},"🟡 1 commit and 1 merged PR in the last 90 days.",[75,2012,2013],{},"🟡 2 commits and 1 merged PR in the last 90 days.",[10,2015,2016,2017,2020],{},"Commit counts cover the default branch, which is ",[89,2018,2019],{},"7.x"," for php-rdkafka. Release figures count GitHub Releases only: php-rdkafka 7.0.0alpha1 was published to PECL on 7 May 2026 without a GitHub Release.",[580,2022,2024],{"id":2023},"maintenance","Maintenance",[51,2026,2027,2053],{},[54,2028,2029],{},[57,2030,2031,2033,2038,2043,2048],{},[60,2032,1876],{},[60,2034,2035],{},[38,2036,16],{"href":586,"rel":2037},[313],[60,2039,2040],{},[38,2041,20],{"href":1097,"rel":2042},[313],[60,2044,2045],{},[38,2046,28],{"href":1824,"rel":2047},[313],[60,2049,2050],{},[38,2051,24],{"href":949,"rel":2052},[313],[70,2054,2055,2070,2084,2101,2118,2135],{},[57,2056,2057,2060,2063,2066,2068],{},[75,2058,2059],{},"Active commit authors (12 mo)",[75,2061,2062],{},"6",[75,2064,2065],{},"7",[75,2067,1942],{},[75,2069,1945],{},[57,2071,2072,2075,2078,2080,2082],{},[75,2073,2074],{},"PR merge distribution (12 mo)",[75,2076,2077],{},"1 account · 100% of non-bot merges",[75,2079,2077],{},[75,2081,2077],{},[75,2083,2077],{},[57,2085,2086,2089,2092,2095,2098],{},[75,2087,2088],{},"Issue backlog",[75,2090,2091],{},"3 open · median age 114 d",[75,2093,2094],{},"0 open issues",[75,2096,2097],{},"8 open · median age 4.1 y",[75,2099,2100],{},"36 open · median age 2.9 y",[57,2102,2103,2106,2109,2112,2115],{},[75,2104,2105],{},"PR backlog",[75,2107,2108],{},"12 open · median age 21 d",[75,2110,2111],{},"1 open · age 1.1 y",[75,2113,2114],{},"16 open · median age 2.2 y",[75,2116,2117],{},"25 open · median age 2.7 y",[57,2119,2120,2123,2126,2129,2132],{},[75,2121,2122],{},"Median PR merge time (90 d)",[75,2124,2125],{},"94.5 d (n=7)",[75,2127,2128],{},"\u003C1 h (n=11)",[75,2130,2131],{},"1.2 d (n=1 — small sample)",[75,2133,2134],{},"1.8 d (n=1 — small sample)",[57,2136,2137,2140,2143,2146,2149],{},[75,2138,2139],{},"Responsiveness assessment",[75,2141,2142],{},"🔴 Median PR merge time 94.5 d exceeds 90 d.",[75,2144,2145],{},"🟡 For the 11 PRs merged in the last 90 d, the median creation-to-merge time was \u003C1 h, but the one open PR is 1.1 y old.",[75,2147,2148],{},"🔴 Only 1 PR merged in 90 d, while 16 open PRs have a median age of 2.2 y.",[75,2150,2151],{},"🔴 Only 1 PR merged in 90 d, while 25 open PRs have a median age of 2.7 y.",[10,2153,2154,2155,2158],{},"PR merge distribution counts non-bot ",[89,2156,2157],{},"mergedBy"," accounts, not maintainer headcount. Median PR merge time measures creation to merge for PRs merged in the last 90 days; unmerged PRs are excluded. None of the four repositories has a published GitHub security advisory.",[580,2160,2162],{"id":2161},"public-usage-and-interest","Public usage and interest",[51,2164,2165,2191],{},[54,2166,2167],{},[57,2168,2169,2171,2176,2181,2186],{},[60,2170,1876],{},[60,2172,2173],{},[38,2174,16],{"href":586,"rel":2175},[313],[60,2177,2178],{},[38,2179,20],{"href":1097,"rel":2180},[313],[60,2182,2183],{},[38,2184,28],{"href":1824,"rel":2185},[313],[60,2187,2188],{},[38,2189,24],{"href":949,"rel":2190},[313],[70,2192,2193,2210,2227,2260,2277],{},[57,2194,2195,2198,2201,2204,2207],{},[75,2196,2197],{},"Stars",[75,2199,2200],{},"2,179",[75,2202,2203],{},"736",[75,2205,2206],{},"92",[75,2208,2209],{},"2,222",[57,2211,2212,2215,2218,2221,2224],{},[75,2213,2214],{},"Forks",[75,2216,2217],{},"276",[75,2219,2220],{},"107",[75,2222,2223],{},"50",[75,2225,2226],{},"427",[57,2228,2229,2232,2239,2246,2253],{},[75,2230,2231],{},"Packagist installs (30 d)",[75,2233,2234],{},[38,2235,2238],{"href":2236,"rel":2237},"https:\u002F\u002Fpackagist.org\u002Fpackages\u002Frdkafka\u002Frdkafka",[313],"8,010",[75,2240,2241],{},[38,2242,2245],{"href":2243,"rel":2244},"https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fmateusjunges\u002Flaravel-kafka",[313],"184,251",[75,2247,2248],{},[38,2249,2252],{"href":2250,"rel":2251},"https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fkoco\u002Fmessenger-kafka",[313],"42,726",[75,2254,2255],{},[38,2256,2259],{"href":2257,"rel":2258},"https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fenqueue\u002Frdkafka",[313],"50,976",[57,2261,2262,2265,2268,2271,2274],{},[75,2263,2264],{},"Packagist installs (all time)",[75,2266,2267],{},"46,734",[75,2269,2270],{},"4,221,219",[75,2272,2273],{},"1,313,271",[75,2275,2276],{},"2,786,064",[57,2278,2279,2282,2284,2287,2289],{},[75,2280,2281],{},"Dependent packages on Packagist",[75,2283,1942],{},[75,2285,2286],{},"24",[75,2288,1942],{},[75,2290,2291],{},"19",[10,2293,2294,2295,2297],{},"Installs include CI builds and transitive dependencies, not unique users. The php-rdkafka column counts only PIE installs of ",[89,2296,256],{},"; PECL, distribution packages, and Docker images are not counted.",[10,2299,2300,2301,2303,2304,2306,2307,2309],{},"Composer packages declare ",[89,2302,269],{},", not ",[89,2305,256],{},", so php-rdkafka's dependent count stays near zero. The Enqueue column covers only the ",[89,2308,954],{}," package.",[580,2311,2313],{"id":2312},"other-libraries-in-this-guide","Other libraries in this guide",[51,2315,2316,2332],{},[54,2317,2318],{},[57,2319,2320,2322,2327],{},[60,2321,1876],{},[60,2323,2324],{},[38,2325,32],{"href":815,"rel":2326},[313],[60,2328,2329],{},[38,2330,1701],{"href":1699,"rel":2331},[313],[70,2333,2334,2344,2353,2362,2372,2382,2392],{},[57,2335,2336,2338,2341],{},[75,2337,1903],{},[75,2339,2340],{},"15 Jun 2026",[75,2342,2343],{},"13 Oct 2023",[57,2345,2346,2348,2350],{},[75,2347,1920],{},[75,2349,550],{},[75,2351,2352],{},"v1.2.2 (15 Mar 2023)",[57,2354,2355,2357,2360],{},[75,2356,1934],{},[75,2358,2359],{},"2",[75,2361,1464],{},[57,2363,2364,2366,2369],{},[75,2365,1950],{},[75,2367,2368],{},"0 (90 d) · 2 (12 mo)",[75,2370,2371],{},"0 (90 d) · 0 (12 mo)",[57,2373,2374,2376,2379],{},[75,2375,2105],{},[75,2377,2378],{},"4 open · median age 4.4 y",[75,2380,2381],{},"7 open · median age 2.7 y",[57,2383,2384,2386,2389],{},[75,2385,2197],{},[75,2387,2388],{},"60",[75,2390,2391],{},"278",[57,2393,2394,2396,2403],{},[75,2395,2231],{},[75,2397,2398],{},[38,2399,2402],{"href":2400,"rel":2401},"https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fjobcloud\u002Fphp-kafka-lib",[313],"9,424",[75,2404,2405],{},[38,2406,2409],{"href":2407,"rel":2408},"https:\u002F\u002Fpackagist.org\u002Fpackages\u002Flonglang\u002Fphpkafka",[313],"90,811",[10,2411,2412,2413,2416],{},"longlang\u002Fphpkafka is developed in the ",[89,2414,2415],{},"swoole\u002Fphpkafka"," repository. Its later tags, v1.2.3 to v1.2.5, have no GitHub Releases; v1.2.5 points to the 13 Oct 2023 commit.",[580,2418,2420],{"id":2419},"overall-repository-signals","Overall repository signals",[219,2422,2423,2428,2433,2438,2446],{},[222,2424,2425,2427],{},[14,2426,16],{}," is active again under its new organization, with 14 commits and 7 merged PRs in the last 90 days; those PRs had a median creation-to-merge time of 94.5 days. Its newest GitHub Release is still 6.0.5; 7.0.0alpha1 has none.",[222,2429,2430,2432],{},[14,2431,20],{}," ships most often, with 13 GitHub releases in the past year, and its 11 merged PRs in the last 90 days had a median merge time under an hour. It also leads Packagist installs, with 184,251 in 30 days.",[222,2434,2435,2437],{},[14,2436,28],{}," had one default-branch commit in the past year, on 1 Oct 2026, the day v0.19 shipped. Its 16 open PRs have a median age of 2.2 years, yet it still had 42,726 installs in 30 days.",[222,2439,2440,2442,2443,2445],{},[14,2441,24],{}," had 47 commits across all transports in the past year but only 2 in the last 90 days. Its 25 open PRs have a median age of 2.7 years; ",[89,2444,954],{}," still had 50,976 installs in 30 days.",[222,2447,2448,2451],{},[14,2449,2450],{},"Among the other libraries",", longlang\u002Fphpkafka has had no commits since 13 Oct 2023, yet its 90,811 installs in 30 days are second only to Laravel Kafka in these tables. php-kafka-lib shipped v2.0.1 and v2.0.2 in 2026 but had no commits in the last 90 days.",[10,2453,2454],{},"Each of the four main repositories had one recorded non-bot PR merger in the past year. These are maintenance and adoption signals, not evidence of runtime quality or feature fit.",[46,2456,2458],{"id":2457},"test-php-kafka-clients-with-kafma","Test PHP Kafka clients with Kafma",[10,2460,2461,2462,2464,2465,2468],{},"In PHP, a ",[89,2463,397],{}," that returns ",[89,2466,2467],{},"true"," and a log line from a handler are weak evidence. A flush can succeed after a record failed delivery, and a consumer can commit past a record its handler rejected.",[10,2470,2471,2472,2476,2477,2481],{},"Kafma is a desktop ",[38,2473,2475],{"href":2474},"\u002F","Kafka GUI"," for checking from outside your PHP process. Its ",[38,2478,2480],{"href":2479},"\u002Ffeatures\u002Fkafka-console","Kafka console"," shows the records on your test cluster and their raw bytes, and it reads consumer group positions without joining the group or committing offsets.",[580,2483,2485],{"id":2484},"inspect-what-each-library-writes","Inspect what each library writes",[10,2487,2488,2489,210],{},"Send a few records from your application and open them in Kafma. Compare each key, value, and header with what the code meant to write, and check the exact bytes in ",[38,2490,2492],{"href":2491},"\u002Fdocs\u002Fconsole\u002Fdecoding-messages","Raw",[10,2494,2495,2496,2498],{},"Several libraries write more than your payload: Laravel Kafka adds a ",[89,2497,1147],{}," header, Enqueue's default serializer wraps the payload in a JSON object, and Messenger's default serializer writes a serialized PHP envelope.",[10,2500,2501,2502,2505,2506,2508,2509,2512],{},"For Avro records, configure Schema Registry in Kafma. ",[14,2503,2504],{},"Decoded"," shows the value resolved through its schema ID. With Confluent's schema-ID wire format, ",[14,2507,2492],{}," starts with ",[89,2510,2511],{},"00"," followed by the four-byte schema ID.",[10,2514,2515,2516,2520],{},"Browse subjects and versions in Kafma's ",[38,2517,2519],{"href":2518},"\u002Ffeatures\u002Fkafka-schema-registry","Schema Registry UI"," to compare them with what the PHP serializer registered.",[10,2522,2523],{},[2524,2525],"img",{"alt":2526,"height":2527,"src":2528,"width":2529},"Kafma showing an Avro record decoded through schema ID 7, with the Decoded and Raw views",1520,"https:\u002F\u002Fmedia.kafma.app\u002Fblog\u002Fkafka-javascript-clients\u002Fconsumer.png",2160,[580,2531,2533],{"id":2532},"compare-partitions-for-the-same-keys","Compare partitions for the same keys",[10,2535,2536],{},"Produce the same keys from your PHP service and a Java service to a test topic, then compare each record's partition in Kafma. Use identical non-empty UTF-8 string keys, and let both producers choose the partition.",[10,2538,2539,2540,111,2542,2545],{},"Libraries built on php-rdkafka hash keys with CRC32 by default and Java uses murmur2, so the same key can land on different partitions; set ",[89,2541,1064],{},[89,2543,2544],{},"murmur2_random"," to align them.",[10,2547,2548],{},"longlang\u002Fphpkafka also hashes keys with CRC32, while RoadRunner's driver uses franz-go's default, which matches Java for keyed records.",[580,2550,2552],{"id":2551},"send-bad-records-to-a-running-consumer","Send bad records to a running consumer",[10,2554,2555,2556,2560],{},"Keep your consumer running. From Kafma's ",[38,2557,2559],{"href":2558},"\u002Fdocs\u002Fconsole\u002Fproducing-messages","producer panel",", send three records in the consumer's expected format to one partition: a valid record, one that deserializes but makes the handler throw, and another valid record.",[10,2562,2563],{},"Then check what happened to the middle record:",[219,2565,2566,2581,2587],{},[222,2567,2568,2571,2572,2574,2575,2577,2578,2580],{},[14,2569,2570],{},"Laravel Kafka:"," With the defaults, it is committed and skipped. With ",[89,2573,1222],{},", check the configured dead-letter topic (",[89,2576,1226],{}," by default) for the record and its ",[89,2579,1230],{}," headers.",[222,2582,2583,2586],{},[14,2584,2585],{},"koco\u002Fmessenger-kafka:"," Messenger's retries appear as new copies at the end of the same topic.",[222,2588,2589,270,2592,2594],{},[14,2590,2591],{},"Enqueue:",[89,2593,459],{}," also produces a copy at the end of the topic.",[580,2596,2598],{"id":2597},"check-committed-offsets-after-failures-and-restarts","Check committed offsets after failures and restarts",[10,2600,2601,2602,2606],{},"Open ",[38,2603,2605],{"href":2604},"\u002Fdocs\u002Fconsole\u002Fconsuming-messages#live-and-watch-group-modes","Watch Group"," for your consumer group and repeat the test. Check whether the committed offset moves past the failed record, and compare it with your application logs.",[10,2608,2609,2610,2613,2614,2616,2617,2621],{},"Then use ",[14,2611,2612],{},"Loop"," to keep records arriving, send the consumer ",[89,2615,1253],{},", restart it with the same group ID, and check which records it reads again. Kafma's ",[38,2618,2620],{"href":2619},"\u002Ffeatures\u002Fkafka-consumer-groups","consumer group UI"," shows lag across every member.",[10,2623,2624],{},[2524,2625],{"alt":2626,"height":2627,"src":2628,"width":2629},"Kafma watching pending and consumed records around a consumer group's committed offsets",1368,"https:\u002F\u002Fmedia.kafma.app\u002Fdocs\u002Fconsole\u002Fconsuming-messages\u002Fwatch-group.png",1562,[10,2631,2632,2636],{},[38,2633,2635],{"href":2634},"\u002Fdownload","Download Kafma"," and connect it to the same test cluster as your PHP service.",[46,2638,2640],{"id":2639},"frequently-asked-questions","Frequently asked questions",[580,2642,2644],{"id":2643},"is-there-an-official-kafka-client-for-php","Is there an official Kafka client for PHP?",[10,2646,2647],{},"No. Apache Kafka's first-party client is Java, and Confluent does not publish a PHP client. php-rdkafka is a community-maintained extension around Confluent's librdkafka, and the other libraries in this guide are community projects.",[580,2649,2651],{"id":2650},"why-does-my-php-producer-exit-without-sending-records","Why does my PHP producer exit without sending records?",[10,2653,2654,2655,2657,2658,2660],{},"If the script ends before ",[89,2656,379],{},", php-rdkafka's producer destructor purges records that are still queued or in flight. Call ",[89,2659,379],{}," with a timeout before the request or script ends, check its return value, and use a delivery report callback for per-record errors.",[580,2662,2664],{"id":2663},"does-laravel-kafka-require-php-rdkafka","Does Laravel Kafka require php-rdkafka?",[10,2666,2667,2668,270,2670,2672,2673,210],{},"Yes. Laravel Kafka 2.13.0 requires ",[89,2669,269],{},[89,2671,273],{},", so it installs only next to php-rdkafka 6.x, not 7.0.0alpha1. pcntl is optional, but the consumer needs it to stop cleanly on ",[89,2674,1253],{},[580,2676,2678],{"id":2677},"does-symfony-messenger-support-kafka","Does Symfony Messenger support Kafka?",[10,2680,2681,2682,2684,2685,2687,2688,210],{},"Not with a built-in transport. Use ",[89,2683,28],{},", or Enqueue's Kafka transport through ",[89,2686,962],{},", which Symfony's documentation points to. Both need php-rdkafka; see ",[38,2689,1312],{"href":104},[580,2691,2693],{"id":2692},"can-kafka-replace-laravels-queue-backend","Can Kafka replace Laravel's queue backend?",[10,2695,2696,2697,2699,2700,2702],{},"Only through a separate queue driver such as ",[89,2698,958],{},"; Laravel Kafka has none. With ",[89,2701,954],{},", that driver sets a delivery delay, even a zero one, for delayed jobs and every job release, and Enqueue's Kafka producer rejects it by throwing.",[10,2704,2705],{},"To start Laravel jobs from Kafka records instead, use Laravel Kafka's queueable handlers, which dispatch one queue job per record.",[580,2707,2709],{"id":2708},"should-i-use-php-rdkafka-70-yet","Should I use php-rdkafka 7.0 yet?",[10,2711,2712,2713,2715,2716,2718,2719,2721],{},"Not in production. 7.0.0alpha1 is an alpha release, and Laravel Kafka, Enqueue, and php-kafka-lib cap ",[89,2714,269],{}," at 6.x. When you test it, note that ",[89,2717,778],{}," returns ",[89,2720,782],{}," on timeout and that PHP 8.1 and librdkafka 1.5.3 are the new minimums.",[10,2723,2724,2725,708,2727,929,2730,210],{},"It adds OAUTHBEARER tokens for ",[89,2726,762],{},[89,2728,2729],{},"Producer::sendOffsetsToTransaction()",[38,2731,16],{"href":127},[580,2733,566],{"id":2734},"do-php-kafka-clients-partition-keys-the-same-way-as-java",[10,2736,2737,2738,2741,2742,111,2744,2746],{},"Not by default. php-rdkafka and its wrappers use librdkafka's ",[89,2739,2740],{},"consistent_random",", which hashes non-empty keys with CRC32; Java uses murmur2. Set ",[89,2743,1064],{},[89,2745,2544],{}," to match Java, given identical key bytes and the same partition count.",[10,2748,2749],{},"longlang\u002Fphpkafka also uses CRC32, while RoadRunner's Kafka driver uses franz-go's default, which matches Java for keyed records.",[580,2751,2753],{"id":2752},"which-php-kafka-clients-support-kip-848","Which PHP Kafka clients support KIP-848?",[10,2755,2756,2757,2759,2760,2762],{},"php-rdkafka supports it when linked against librdkafka 2.12.0 or later, with Kafka 4.0+ brokers and ",[89,2758,572],{},"; ",[89,2761,245],{}," shows the librdkafka version.",[10,2764,2765],{},"Wrappers keep that support unless they register an eager rebalance callback. Laravel Kafka, Enqueue, and php-kafka-lib register none by default; koco\u002Fmessenger-kafka always does, so KIP-848 does not work with it.",[10,2767,2768],{},"Without php-rdkafka, longlang\u002Fphpkafka supports only the classic protocol, and lisachenko\u002Fkafka-client implements KIP-848 in pure PHP.",[580,2770,2772],{"id":2771},"does-php-rdkafka-work-with-aws-msk-iam","Does php-rdkafka work with AWS MSK IAM?",[10,2774,2775],{},"Not directly. librdkafka does not generate MSK IAM tokens, so your code must create a signed token in an OAUTHBEARER refresh callback, using a custom signer built on the AWS SDK for PHP's SigV4 support.",[10,2777,2778,2779,2781,2782,2784],{},"In php-rdkafka 6.0.5, ",[89,2780,762],{}," cannot set that token; 7.0.0alpha1 adds ",[89,2783,758],{},", but Laravel Kafka, Enqueue, and php-kafka-lib do not allow 7.0 yet. RoadRunner's Kafka driver supports MSK IAM directly.",[10,2786,2787],{},"SASL\u002FSCRAM is an alternative on MSK Provisioned clusters that enable it; MSK Serverless requires IAM.",[46,2789,2791],{"id":2790},"conclusion","Conclusion",[10,2793,2794,2795,2797],{},"Laravel applications should start with Laravel Kafka. It commits and skips failed records by default: use retries for transient failures, and configure a dead-letter topic or ",[89,2796,91],{}," for records that still fail.",[10,2799,2800],{},"Symfony Messenger applications can use koco\u002Fmessenger-kafka, or Enqueue's transport if they already use Enqueue.",[10,2802,2803],{},"Plain PHP services can use php-rdkafka directly, or php-kafka-lib for manual commits by default.",[10,2805,2806,2807,2809],{},"Stay on php-rdkafka 6.0.5 until 7.0 is stable and your wrapper allows it. Flush producers before PHP-FPM requests end. Run consumers as CLI workers under a process manager, commit only after processing succeeds, and handle ",[89,2808,1253],{}," for graceful shutdown.",[10,2811,2812],{},"If you cannot install the extension, use HTTP through a REST Proxy or a pure PHP client, and weigh their maintenance and feature limits.",[10,2814,2815],{},"This guide is maintained by the team behind Kafma.",{"title":2817,"searchDepth":2818,"depth":2818,"links":2819},"",3,[2820,2822,2823,2828,2832,2833,2834,2835,2843,2849,2860],{"id":48,"depth":2821,"text":49},2,{"id":213,"depth":2821,"text":214},{"id":290,"depth":2821,"text":291,"children":2824},[2825,2826,2827],{"id":16,"depth":2818,"text":16},{"id":32,"depth":2818,"text":32},{"id":944,"depth":2818,"text":24},{"id":1087,"depth":2821,"text":1088,"children":2829},[2830,2831],{"id":1091,"depth":2818,"text":1092},{"id":1311,"depth":2818,"text":1312},{"id":1479,"depth":2821,"text":209},{"id":1544,"depth":2821,"text":1545},{"id":1684,"depth":2821,"text":41},{"id":1777,"depth":2821,"text":1778,"children":2836},[2837,2838,2839,2840,2841,2842],{"id":1800,"depth":2818,"text":1801},{"id":1866,"depth":2818,"text":1867},{"id":2023,"depth":2818,"text":2024},{"id":2161,"depth":2818,"text":2162},{"id":2312,"depth":2818,"text":2313},{"id":2419,"depth":2818,"text":2420},{"id":2457,"depth":2821,"text":2458,"children":2844},[2845,2846,2847,2848],{"id":2484,"depth":2818,"text":2485},{"id":2532,"depth":2818,"text":2533},{"id":2551,"depth":2818,"text":2552},{"id":2597,"depth":2818,"text":2598},{"id":2639,"depth":2821,"text":2640,"children":2850},[2851,2852,2853,2854,2855,2856,2857,2858,2859],{"id":2643,"depth":2818,"text":2644},{"id":2650,"depth":2818,"text":2651},{"id":2663,"depth":2818,"text":2664},{"id":2677,"depth":2818,"text":2678},{"id":2692,"depth":2818,"text":2693},{"id":2708,"depth":2818,"text":2709},{"id":2734,"depth":2818,"text":566},{"id":2752,"depth":2818,"text":2753},{"id":2771,"depth":2818,"text":2772},{"id":2790,"depth":2821,"text":2791},"2026-10-16","php-rdkafka 7.0 is in alpha; its last stable release shipped in 2024. Compare Laravel Kafka, Symfony Messenger, and Enqueue.","md",{},true,null,"\u002Fblog\u002Fkafka-php-clients",false,{"title":5,"description":2862},{"loc":2867},"blog\u002Fkafka-php-clients",[2873,2874],"Kafka Client Libraries","PHP","S_KGdHJSNYklT4MeQn_oB7o93uqRvzm624gGI02fb2U",1792158371564]