Browse Source

Add ReactPHP (#6590)

* Add ReactPHP

* Delete comment

* Delete comment
Joan Miquel 4 years ago
parent
commit
34c216de4a

+ 13 - 0
frameworks/PHP/reactphp/README.md

@@ -0,0 +1,13 @@
+# ReactPH Framework Benchmarking Test
+
+This is the [ReactPHP Framework](https://reactphp.org/) Event-driven, non-blocking I/O with PHP.
+
+## Test URLs
+
+### JSON Encoding Test
+
+http://localhost:8080/json
+
+### Plaintext Test
+
+http://localhost:8080/plaintext

+ 141 - 0
frameworks/PHP/reactphp/app.php

@@ -0,0 +1,141 @@
+<?php
+use Psr\Http\Message\ServerRequestInterface as Request;
+use React\Http\Message\Response;
+
+function init()
+{
+    global $world, $fortune, $update;
+    $pdo = new PDO(
+        'mysql:host=tfb-database;dbname=hello_world',
+        'benchmarkdbuser',
+        'benchmarkdbpass',
+        [
+            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+            PDO::ATTR_EMULATE_PREPARES   => false
+        ]
+    );
+    $world   = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+    $update  = $pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?');
+    $fortune = $pdo->prepare('SELECT id,message FROM Fortune');
+    $fortune->setFetchMode(PDO::FETCH_KEY_PAIR);
+}
+
+function router(Request $request)
+{
+    return match($request->getUri()->getPath()) {
+        '/plaintext' => text(),
+        '/json'      => json(), 
+        '/db'        => db(),
+        '/fortunes'  => fortune(),
+        '/query'     => query($request),
+        '/update'    => updateraw($request),
+        // '/info'      => info(),
+        default      => new Response(404, [], 'Error 404'),
+    };
+}
+
+function text()
+{
+    return new Response(200, [
+        'Content-Type' => 'text/plain'
+    ], 'Hello, World!');
+}
+
+function json()
+{
+    return new Response(200, [
+        'Content-Type' => 'application/json'
+    ], json_encode(['message' => 'Hello, World!']));
+}
+
+function db()
+{
+    global $world;
+
+    $world->execute([mt_rand(1, 10000)]);
+
+    return new Response(200, [
+        'Content-Type' => 'application/json'
+    ], json_encode($world->fetch()));
+}
+
+function query($request)
+{
+    global $world;
+
+    $query_count = 1;
+    $q = (int) $request->getQueryParams()['q'];
+    if ($q > 1) {
+        $query_count = min($q, 500);
+    }                                                          
+
+    while ($query_count--) {
+        $world->execute([mt_rand(1, 10000)]);
+        $arr[] = $world->fetch();
+    }
+
+    return new Response(200, [
+        'Content-Type' => 'application/json'
+    ], json_encode($arr));
+}
+
+function updateraw($request)
+{
+    global $world, $update;
+
+    $query_count = 1;
+    $q = (int) $request->getQueryParams()['q'];
+    if ($q > 1) {
+        $query_count = min($q, 500);
+    }
+
+    while ($query_count--) {
+        $id = mt_rand(1, 10000);
+        $world->execute([$id]);
+        $item = $world->fetch();
+        $update->execute(
+            [$item['randomNumber'] = mt_rand(1, 10000), $id]
+        );
+
+        $arr[] = $item;
+    }
+
+    // $pdo->beginTransaction();
+    // foreach($arr as $world) {
+    //     $update->execute([$world['randomNumber'], $world['id']]);
+    // }
+    // $pdo->commit();
+    return new Response(200, [
+        'Content-Type' => 'application/json'
+    ], json_encode($arr));
+}
+
+function fortune()
+{
+    global $fortune;
+
+    $fortune->execute();
+
+    $arr    = $fortune->fetchAll();
+    $arr[0] = 'Additional fortune added at request time.';
+    asort($arr);
+
+    $html = '';
+    foreach ($arr as $id => $message) {
+        $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
+        $html .= "<tr><td>$id</td><td>$message</td></tr>";
+    }
+
+    return new Response(200, [
+        'Content-Type' => 'text/html; charset=UTF-8',
+    ], "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>$html</table></body></html>"
+    );
+}
+
+/* function info()
+{
+    ob_start();
+    phpinfo();
+    return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean());
+}
+ */

+ 28 - 0
frameworks/PHP/reactphp/benchmark_config.json

@@ -0,0 +1,28 @@
+{
+  "framework": "reactphp",
+  "tests": [{
+    "default": {
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/query?q=",
+      "fortune_url": "/fortunes",
+      "update_url": "/update?q=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "framework": "reactphp",
+      "language": "PHP",
+      "flavor": "PHP7",
+      "database": "MySQL",
+      "orm": "Raw",
+      "platform": "reactphp",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "reactphp",
+      "notes": "",
+      "versus": "php"
+    }
+  }]
+}

+ 9 - 0
frameworks/PHP/reactphp/composer.json

@@ -0,0 +1,9 @@
+{
+    "require": {
+        "php": ">=5.3.0",
+        "psr/http-message": "^1.0",
+        "react/event-loop": "^1.1",
+        "react/http": "^1.3",
+        "react/socket": "^1.6"
+    }
+}

+ 19 - 0
frameworks/PHP/reactphp/config.toml

@@ -0,0 +1,19 @@
+[framework]
+name = "reactphp"
+
+[main]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/query?q="
+urls.update = "/update?q="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Platform"
+database = "MySQL"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "reactphp"
+webserver = "None"
+versus = "php"

+ 13 - 0
frameworks/PHP/reactphp/deploy/conf/php.ini

@@ -0,0 +1,13 @@
+opcache.enable=1
+opcache.enable_cli=1
+opcache.validate_timestamps=0
+opcache.save_comments=0
+opcache.enable_file_override=1
+opcache.huge_code_pages=1
+
+mysqlnd.collect_statistics = Off
+
+memory_limit = 512M
+
+opcache.jit_buffer_size=128M
+opcache.jit=tracing

+ 30 - 0
frameworks/PHP/reactphp/reactphp.dockerfile

@@ -0,0 +1,30 @@
+FROM ubuntu:21.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null
+RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php
+RUN apt-get update -yqq > /dev/null && \
+    apt-get install -yqq git unzip wget curl build-essential \
+    php8.0-cli php8.0-mbstring php8.0-dev php8.0-xml php8.0-curl php8.0-mysql > /dev/null
+
+# An extension is required!
+# We deal with concurrencies over 1k, which stream_select doesn't support.
+RUN wget http://pear.php.net/go-pear.phar --quiet && php go-pear.phar
+#RUN apt-get install -y libuv1-dev > /dev/null
+RUN apt-get install -y libevent-dev > /dev/null
+#RUN pecl install uv-0.2.4 > /dev/null && echo "extension=uv.so" > /etc/php/8.0/cli/conf.d/uv.ini
+RUN pecl install event-3.0.4 > /dev/null && echo "extension=event.so" > /etc/php/8.0/cli/conf.d/event.ini
+
+ADD ./ /reactphp
+WORKDIR /reactphp
+
+COPY deploy/conf/* /etc/php/8.0/cli/conf.d/
+
+COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+
+RUN composer install --prefer-dist --optimize-autoloader --no-dev --quiet
+
+EXPOSE 8080
+
+CMD php server.php

+ 19 - 0
frameworks/PHP/reactphp/server.php

@@ -0,0 +1,19 @@
+<?php
+
+require __DIR__ . '/vendor/autoload.php';
+require_once __DIR__.'/app.php';
+
+init();
+
+$loop = React\EventLoop\Factory::create();
+
+$server = new React\Http\Server($loop, function (Psr\Http\Message\ServerRequestInterface $request) {
+    return router($request);
+});
+
+$socket = new React\Socket\Server('0.0.0.0:8080', $loop);
+$server->listen($socket);
+
+echo "React Server running at http://0.0.0.0:8080\n";
+
+$loop->run();