Skip to content

[php] Slim to v4, php8.1 and adapterman #7660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions frameworks/PHP/slim/benchmark_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,50 @@
"display_name": "slim",
"notes": "",
"versus": "php"
},
"workerman": {
"plaintext_url": "/plaintext",
"json_url": "/json",
"db_url": "/db",
"query_url": "/dbs?queries=",
"update_url": "/updates?queries=",
"fortune_url": "/fortunes",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
"database": "MySQL",
"framework": "slim",
"language": "PHP",
"flavor": "PHP8",
"orm": "Raw",
"platform": "workerman",
"webserver": "none",
"os": "Linux",
"database_os": "Linux",
"display_name": "slim-workerman",
"notes": "",
"versus": "php"
},
"workerman-pgsql": {
"db_url": "/db",
"query_url": "/dbs?queries=",
"update_url": "/updates?queries=",
"fortune_url": "/fortunes",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
"database": "postgres",
"framework": "slim",
"language": "PHP",
"flavor": "PHP8",
"orm": "Raw",
"platform": "workerman",
"webserver": "none",
"os": "Linux",
"database_os": "Linux",
"display_name": "slim-workerman-pgsql",
"notes": "Optimized for Workerman",
"versus": "php"
}
}]
}
12 changes: 10 additions & 2 deletions frameworks/PHP/slim/composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
{
"require": {
"slim/slim": "3.12.4",
"slim/php-view": "3.2.0"
"slim/slim": "^4.10",
"slim/php-view": "3.2.0",
"slim/psr7": "1.*",
"slim/http": "1.*",
"php-di/php-di": "^6.4"
},
"autoload": {
"psr-4": {
"Db\\": "db/"
}
}
}
92 changes: 92 additions & 0 deletions frameworks/PHP/slim/db/Raw.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
namespace db;

use PDO;
use PDOStatement;

class Raw
{
private static PDO $instance;
public static PDOStatement $db;
public static PDOStatement $fortune;
public static PDOStatement $random;
/**
* @var []PDOStatement
*/
private static $update;

public static function init()
{
$pdo = new PDO(
'pgsql:host=tfb-database;dbname=hello_world',
'benchmarkdbuser',
'benchmarkdbpass',
[
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
]
);

self::$fortune = $pdo->prepare('SELECT id,message FROM Fortune');
self::$random = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id = ?');
self::$instance = $pdo;
}

/**
* Postgres bulk update
*
* @param array $worlds
* @return void
*/
public static function update(array $worlds)
{
$rows = count($worlds);

if (!isset(self::$update[$rows])) {
$sql = 'UPDATE world SET randomNumber = CASE id'
. str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows)
. 'END WHERE id IN ('
. str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)';

self::$update[$rows] = self::$instance->prepare($sql);
}

$val = [];
$keys = [];
foreach ($worlds as $world) {
$val[] = $keys[] = $world['id'];
$val[] = $world['randomNumber'];
}

self::$update[$rows]->execute([...$val, ...$keys]);
}

/**
* Alternative bulk update in Postgres
*
* @param array $worlds
* @return void
*/
public static function update2(array $worlds)
{
$rows = count($worlds);

if (!isset(self::$update[$rows])) {
$sql = 'UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES '
. implode(', ', array_fill(0, $rows, '(?::INTEGER, ?::INTEGER)')) .
' ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id';

self::$update[$rows] = self::$instance->prepare($sql);
}

$val = [];
foreach ($worlds as $world) {
$val[] = $world['id'];
$val[] = $world['randomNumber'];
//$update->bindParam(++$i, $world['id'], PDO::PARAM_INT);
}

self::$update[$rows]->execute($val);
}
}
16 changes: 16 additions & 0 deletions frameworks/PHP/slim/deploy/conf/cli-php.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#zend_extension=opcache.so
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

disable_functions=header,header_remove,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit
116 changes: 65 additions & 51 deletions frameworks/PHP/slim/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,66 +3,72 @@

require_once __DIR__.'/vendor/autoload.php';

$app = new Slim\App(array(
'db' => function ($c) {
$pdo = new PDO('mysql:host=tfb-database;dbname=hello_world;charset=utf8', 'benchmarkdbuser', 'benchmarkdbpass', array(
PDO::ATTR_PERSISTENT => true,
));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

return $pdo;
},

'view' => function ($c) {
return new Slim\Views\PhpRenderer("templates/");
}
));
use DI\Container;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Views\PhpRenderer;

//global $app; // workerman

$container = new Container();

$container->set('db', new PDO(
'mysql:host=tfb-database;dbname=hello_world;charset=utf8',
'benchmarkdbuser',
'benchmarkdbpass',
[
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
//PDO::ATTR_EMULATE_PREPARES => false, // workerman
]));

$container->set('view', new PhpRenderer('templates'));

AppFactory::setContainer($container);
$app = AppFactory::create();


// Test 1: Plaintext
$app->get('/plaintext', function ($request, $response) {
return $response
$app->get('/plaintext', fn(Request $request, Response $response) =>
$response
->write('Hello, World!')
->withHeader('Content-Type', 'text/plain')
;
});
);

// Test 2: JSON serialization
$app->get('/json', function ($request, $response) {
return $response
->withJson(array('message' => 'Hello, World!'))
->withHeader('Content-Type', 'application/json') // fixes utf-8 warning
;
});
$app->get('/json', fn(Request $request, Response $response) =>
$response
->withJson(['message' => 'Hello, World!'])
);

// Test 3: Single database query
$app->get('/db', function ($request, $response) {
$sth = $this->db->prepare('SELECT * FROM World WHERE id = ?');
$sth->execute(array(mt_rand(1, 10000)));
$app->get('/db', function (Request $request, Response $response) {
$sth = $this->get('db')->prepare('SELECT * FROM World WHERE id = ?');
$sth->execute([mt_rand(1, 10000)]);
$world = $sth->fetch();
# Cast fields to int so they don't get wrapped with quotes
$world['id'] = (int) $world['id'];
$world['randomNumber'] = (int) $world['randomNumber'];

return $response
->withJson($world)
->withHeader('Content-Type', 'application/json') // fixes utf-8 warning
;
->withJson($world);
});

// Test 4: Multiple database queries
$app->get('/dbs', function ($request, $response) {
$app->get('/dbs', function (Request $request, Response $response) {
$queries = $request->getParam('queries');
if (is_numeric($queries)) {
$queries = max(1, min($queries, 500));
} else {
$queries = 1;
}

$sth = $this->db->prepare('SELECT * FROM World WHERE id = ?');
$worlds = array();
$sth = $this->get('db')->prepare('SELECT * FROM World WHERE id = ?');
$worlds = [];
for ($i = 0; $i < $queries; ++$i) {
$sth->execute(array(mt_rand(1, 10000)));
$sth->execute([mt_rand(1, 10000)]);
$world = $sth->fetch();
# Cast fields to int so they don't get wrapped with quotes
$world['id'] = (int) $world['id'];
Expand All @@ -71,52 +77,60 @@
}

return $response
->withJson($worlds)
->withHeader('Content-Type', 'application/json') // fixes utf-8 warning
;
->withJson($worlds);
});

// Test 5: Updates
$app->get('/updates', function ($request, $response) {
$app->get('/updates', function (Request $request, Response $response) {
$queries = $request->getParam('queries');
if (is_numeric($queries)) {
$queries = max(1, min($queries, 500));
} else {
$queries = 1;
}

$sth = $this->db->prepare('SELECT * FROM World WHERE id = ?');
$updateSth = $this->db->prepare('UPDATE World SET randomNumber = ? WHERE id = ?');
$sth = $this->get('db')->prepare('SELECT * FROM World WHERE id = ?');
$updateSth = $this->get('db')->prepare('UPDATE World SET randomNumber = ? WHERE id = ?');

$worlds = array();
$worlds = [];
for ($i = 0; $i < $queries; ++$i) {
$id = mt_rand(1, 10000);
$random_number = mt_rand(1, 10000);
$sth->execute(array($id));
$sth->execute([$id]);
$world = $sth->fetch();
# Cast fields to int so they don't get wrapped with quotes
$world['id'] = (int) $world['id'];
$world['randomNumber'] = $random_number;

$updateSth->execute(array($world['randomNumber'], $world['id']));
$updateSth->execute([$world['randomNumber'], $world['id']]);

$worlds[] = $world;
}

return $response
->withJson($worlds)
->withHeader('Content-Type', 'application/json') // fixes utf-8 warning
;
->withJson($worlds);
});

// Test 6: Fortunes
$app->get('/fortunes', function ($request, $response) {
$fortunes = $this->db->query('SELECT * FROM Fortune')->fetchAll(PDO::FETCH_KEY_PAIR);
$app->get('/fortunes', function (Request $request, Response $response) {
$fortunes = $this->get('db')->query('SELECT * FROM Fortune')->fetchAll(PDO::FETCH_KEY_PAIR);

$fortunes[0] = 'Additional fortune added at request time.';
asort($fortunes);

return $this->view->render($response, "fortunes.php", ["fortunes" => $fortunes]);
return $this->get('view')->render($response, 'fortunes.php', ['fortunes' => $fortunes]);
});

$app->run();
$app->run(); // comented with workerman

// used by Workerman
function run(): string
{
global $app;
ob_start();

$app->run();
header(HeaderDate::$date); // To pass the bench, nginx auto add it

return ob_get_clean();
}
Loading