🚀 Production-Ready · v3.0

Tài liệu GracePL

Ngôn ngữ lập trình production-ready với cú pháp quen thuộc như PHP, hiệu năng cao của Go. Bytecode VM, concurrency thực sự, module system, structured logging, metrics, circuit breaker và hơn 335 hàm tích hợp.

Bytecode VM

Biên dịch sang bytecode, chạy nhanh hơn interpreted scripting.

🔀

Concurrency thực sự

spawn, channel, WaitGroup, select — dùng goroutine của Go.

📦

Module System

import / import_as / export — isolation đầy đủ, không global leak.

🌐

Web built-in

HTTP server, WebSocket, routing, CORS, rate limiting, TLS — production-ready.

📊

Production Observability

JSON logging, Prometheus metrics, request tracing, circuit breaker, cron.

🗄️

Database + Redis

MySQL, PostgreSQL, SQLite, Redis — connection pooling, transactions, Redis sessions.

1 Cài đặt

Tải binary (Windows)

> curl -L https://github.com/ghoullp/gracepl-lang/releases/latest/download/gracepl-windows-amd64.zip -o gracepl.zip
> tar -xf gracepl.zip; mv gracepl.exe C:\Windows\System32\

Tải binary (Linux / macOS)

$ curl -fsSL https://raw.githubusercontent.com/ghoullp/gracepl-lang/main/install.sh | bash

Build từ source (cần Go 1.22+)

bash
git clone https://github.com/ghoullp/gracepl-lang
cd gracepl-lang
go build -o gracepl .
./gracepl --version   # GracePL v3.0
      

Kiểm tra cài đặt thành công

bash
gracepl --version
# GracePL v3.0 (go1.24.0)

gracepl run hello.gp
gracepl test ./examples/
gracepl lsp     # khởi động Language Server

2 Quick Start

Hello World

gracepl
<gp>
echo "Hello, World!\n";
bash
gracepl run hello.gp
# Hello, World!

Ví dụ thực tế: REST API đơn giản

gracepl
<gp>
db_connect("mysql://user:pass@localhost/mydb");

http_handle("/api/users", function($req) {
    if ($req["method"] == "GET") {
        $users = db_query("SELECT id, name, email FROM users");
        http_json(["data" => $users, "count" => count($users)]);
    } elseif ($req["method"] == "POST") {
        $body = json_decode($req["body"]);
        db_exec("INSERT INTO users (name, email) VALUES (?, ?)",
                [$body["name"], $body["email"]]);
        http_json(["status" => "created"], 201);
    }
});

// Production middleware
http_request_id();
http_panic_recover();
http_cors_whitelist(["https://myapp.com"]);
metrics_enable("/metrics");
log_format("json");

http_serve(":8080");

Ví dụ: Concurrency

gracepl
<gp>
$results = chan_make(10);
$jobs    = [1, 2, 3, 4, 5];

// Chạy song song
foreach ($jobs as $n) {
    $num = $n;
    spawn {
        $results <- $num * $num;  // tính toán và gửi kết quả
    };
}

// Thu gom kết quả
$total = 0;
foreach ($jobs as $_) {
    $total += <-$results;
}

echo "Tổng bình phương: $total\n"; // 55

3 VS Code Extension

GracePL có extension chính thức cho Visual Studio Code với đầy đủ tính năng hiện đại:

  • Syntax highlighting (TextMate grammar)
  • Autocomplete — hàm, keyword, snippet
  • Hover documentation
  • Diagnostics real-time (lỗi cú pháp, undefined variable)
  • Go to definition / Find all references
  • Format on save
  • Outline view
Cài đặt: Mở VS Code → Extensions (Ctrl+Shift+X) → tìm GracePL → Install. Extension tự động tìm gracepl lsp hoặc dùng đường dẫn binary trong settings.

4 Cấu trúc file

Mọi file GracePL phải bắt đầu bằng tag <gp>:

gracepl
<gp>
// Comment một dòng
# Cũng là comment

/*
   Comment
   nhiều dòng
*/

echo "Code của bạn ở đây";

File không cần tag đóng. Extension chuẩn là .gp.

5 Kiểu dữ liệu

Kiểu Mô tả Ví dụ
int Số nguyên 64-bit 42, -7, 0
float Số thực 64-bit IEEE 754 3.14, -0.5
string Chuỗi UTF-8 bất biến "hello", 'world'
bool Boolean true, false
null Giá trị null null
array Mảng có chỉ số số [1, 2, 3]
map Map string-key ["a" => 1]
object Instance của class new User()
closure Hàm ẩn danh fn($x) => $x*2
resource Handle C (channel, DB, file…) chan_make()

Ép kiểu

gracepl
<gp>
$i = (int)"42";       // 42
$f = (float)"3.14";   // 3.14
$s = (string)100;     // "100"
$b = (bool)1;         // true
$a = (array)"hello";  // ["hello"]

// Kiểm tra kiểu
is_int($i);     // true
is_string($s);  // true
gettype($f);    // "double"

6 Biến & Scope

gracepl
<gp>
// Gán biến
$name  = "Alice";
$age   = 30;
$items = [1, 2, 3];

// Null coalescing
$val = $maybeNull ?? "default";
$cfg["timeout"] ??= 30;

// Biến trong hàm
function demo() {
    $local = "chỉ trong hàm này";

    // Truy cập biến global
    global $name;
    echo $name;  // Alice
}

// Global declaration + init
global $counter = 0;

7 Toán tử

$a + $b    // cộng
$a - $b    // trừ
$a * $b    // nhân
$a / $b    // chia
$a % $b    // chia lấy dư
$a ** $b   // lũy thừa
$a . $b    // nối chuỗi
$x += 5;   $x -= 2;   $x *= 3;
$x /= 4;   $x %= 7;   $x .= " text";
$a == $b    // bằng (loose)
$a != $b    // khác (loose)
$a === $b   // bằng chặt (kiểm tra cả kiểu)
$a !== $b   // khác chặt
$a < $b    $a > $b    $a <= $b    $a >= $b

// Null coalescing
$a ?? $b      // $b nếu $a là null
$a ??= $b;    // gán $b cho $a nếu $a là null
$a && $b    // AND (short-circuit)
$a || $b    // OR  (short-circuit)
!$a         // NOT
$a and $b   // AND (precedence thấp hơn)
$a or  $b   // OR  (precedence thấp hơn)

// Ternary
$x = $cond ? "có" : "không";

// instanceof
$obj instanceof ClassName
$a & $b    // AND
$a | $b    // OR
$a ^ $b    // XOR
~$a        // NOT
$a << $n   // shift left
$a >> $n   // shift right

8 String

gracepl
<gp>
$name = "Alice";

// Double-quoted — hỗ trợ interpolation
echo "Xin chào, $name!";            // Xin chào, Alice!
echo "Phần tử: {$arr[0]}";
echo "Method: {$obj->getName()}";

// Single-quoted — không interpolation
echo 'Đây là $name';                // Đây là $name

// Heredoc
$text = <<<EOT
Dòng 1
Biến: $name
EOT;

// Escape sequences
"\n"  "\t"  "\\"  "\""  "\$"

// Hàm phổ biến
strlen($s)
strtoupper($s) / strtolower($s)
substr($s, 0, 5)
str_replace("old", "new", $s)
strpos($s, "needle")           // false nếu không tìm thấy
trim($s) / ltrim() / rtrim()
explode(",", $s)               // split → array
implode(", ", $arr)            // join ← array
str_contains($s, "sub")
str_starts_with($s, "pre")
str_ends_with($s, "suf")
sprintf("%.2f", 3.14159)
preg_match('/\d+/', $s, $m)
preg_replace('/\s+/', ' ', $s)

9 Điều khiển luồng

gracepl
<gp>
// if / elseif / else
if ($score >= 90) {
    echo "Xuất sắc";
} elseif ($score >= 70) {
    echo "Khá";
} else {
    echo "Trung bình";
}

// while
$i = 0;
while ($i < 5) { $i++; }

// for
for ($i = 0; $i < 10; $i++) {
    if ($i == 5) continue;
    if ($i == 9) break;
    echo $i;
}

// foreach
foreach ($items as $item) { echo $item; }
foreach ($map as $key => $val) { echo "$key=$val"; }

// switch
switch ($role) {
    case "admin":  echo "Quản trị"; break;
    case "editor": echo "Biên tập"; break;
    default:       echo "Khách";
}

// match (expression)
$label = match ($code) {
    200     => "OK",
    404     => "Not Found",
    500     => "Server Error",
    default => "Unknown",
};

10 Hàm

gracepl
<gp>
// Hàm thông thường
function greet(string $name, string $prefix = "Chào"): string {
    return "$prefix, $name!";
}

// Variadic
function sum(...$nums): int {
    return array_sum($nums);
}

// Closure — capture bằng use
$mult = 3;
$triple = function($x) use ($mult) { return $x * $mult; };

// Arrow function — auto-capture scope ngoài
$double = fn($x) => $x * 2;

// Higher-order
$numbers = [1, 2, 3, 4, 5];
$doubled  = array_map(fn($x) => $x * 2, $numbers);
$evens    = array_filter($numbers, fn($x) => $x % 2 == 0);
$total    = array_reduce($numbers, fn($c, $x) => $c + $x, 0);

// Đệ quy
function fib($n) {
    if ($n <= 1) return $n;
    return fib($n-1) + fib($n-2);
}

11 Mảng & Map

gracepl
<gp>
// Array
$arr = [1, 2, 3];
$arr[] = 4;            // thêm vào cuối
count($arr);           // 4

// Destructuring
[$a, $b, $c] = $arr;
[$first, , $third] = [10, 20, 30];

// Map
$user = [
    "name"  => "Alice",
    "age"   => 30,
    "roles" => ["admin", "user"]
];
echo $user["name"];        // Alice
$user["email"] = "a@b.c"; // thêm
unset($user["age"]);       // xóa

// Hàm array phổ biến
array_push($arr, $val);    // sửa $arr trực tiếp — KHÔNG gán lại!
array_pop($arr);
array_shift($arr);         // xóa đầu
array_unshift($arr, $val); // thêm đầu

in_array($needle, $arr);
array_search($needle, $arr);
array_keys($map);
array_values($arr);
array_merge($arr1, $arr2);
array_unique($arr);
array_reverse($arr);
array_chunk($arr, 3);

sort($arr);
usort($arr, fn($a, $b) => $a - $b);

array_sum($arr);
array_product($arr);

12 Class & OOP

gracepl
<gp>
class Person {
    public string $name;
    private int $age;
    static $count = 0;

    function __construct(string $name, int $age) {
        $this->name = $name;
        $this->age  = $age;
        self::$count++;
    }

    public function greet(): string {
        return "Chào, tôi là {$this->name}!";
    }

    static function getCount(): int { return self::$count; }

    // Magic methods
    function __toString(): string { return "Person({$this->name})"; }
    function __get($prop)        { return null; }
    function __set($prop, $val)  { }
    function __call($m, $args)   { }
}

// Kế thừa
class Employee extends Person {
    function __construct(string $name, int $age, public string $company) {
        parent::__construct($name, $age);
    }
}

$p = new Person("Alice", 30);
echo $p->greet();
echo Person::getCount();  // 1
echo $p instanceof Person;   // true

13 Interface & Trait

gracepl
<gp>
interface Serializable {
    function serialize(): string;
    function unserialize(string $data): void;
}

abstract class Shape {
    abstract function area(): float;
    function describe(): string { return "Diện tích: " . $this->area(); }
}

trait Timestamps {
    public $createdAt;
    function setTimestamps() { $this->createdAt = time(); }
}

class Circle extends Shape implements Serializable {
    use Timestamps;

    function __construct(private float $r) { $this->setTimestamps(); }

    function area(): float { return M_PI * $this->r ** 2; }

    function serialize(): string { return json_encode(["r" => $this->r]); }
    function unserialize(string $d): void { $this->r = json_decode($d)["r"]; }
}

final class Singleton {
    static $inst = null;
    static function get(): self { return self::$inst ??= new self(); }
}

14 Enum

gracepl
<gp>
// Integer enum (auto-increment từ 0)
enum Direction {
    NORTH,   // 0
    SOUTH,   // 1
    EAST,    // 2
    WEST     // 3
}

// Integer enum với giá trị tùy chỉnh
enum HttpStatus {
    OK     = 200,
    NOT_FOUND = 404,
    ERROR  = 500
}

// String enum
enum Color {
    RED   = "#FF0000",
    GREEN = "#00FF00",
    BLUE  = "#0000FF"
}

echo Direction::EAST;   // 2
echo HttpStatus::OK;    // 200
echo Color::RED;        // #FF0000

switch ($status) {
    case HttpStatus::OK:      echo "Thành công"; break;
    case HttpStatus::NOT_FOUND: echo "Không tìm thấy"; break;
}

15 Type Hinting

gracepl
<gp>
// Tham số + return type
function add(int $a, int $b): int {
    return $a + $b;
}

// Nullable
function findUser(?int $id): ?array {
    if ($id === null) return null;
    return db_query_row("SELECT * FROM users WHERE id = ?", [$id]);
}

// Union type
function process(int|string $value): string {
    return (string)$value;
}

// void return
function log(string $msg): void {
    file_put_contents("app.log", $msg . "\n", FILE_APPEND);
}

// Class type
function greet(Person $p): string {
    return "Chào {$p->name}";
}
Lưu ý: Type hints được ghi nhận để hỗ trợ tooling (LSP autocomplete, docs). Runtime không enforce — consistent với triết lý dynamic scripting.

16 Exception Handling

gracepl
<gp>
// Custom exception
class ValidationError extends Error {
    function __construct(string $msg, private string $field) {
        parent::__construct($msg);
    }
    function getField(): string { return $this->field; }
}

function validateEmail(string $email): void {
    if (!str_contains($email, "@")) {
        throw new ValidationError("Email không hợp lệ", "email");
    }
}

// try / catch / finally
try {
    validateEmail("not-an-email");
    $result = doRiskyOp();
} catch (ValidationError $e) {
    echo "Validation: " . $e->getMessage() . " [" . $e->getField() . "]";
} catch (NetworkError|TimeoutError $e) {
    echo "Network: " . $e->getMessage();
} catch ($e) {
    echo "Lỗi chung: " . $e->getMessage();
} finally {
    cleanup();  // luôn chạy
}

// Error chaining
function fetchUser($id) {
    try {
        return db_query_row("SELECT * FROM users WHERE id = ?", [$id]);
    } catch ($e) {
        throw error_wrap($e, "fetchUser($id) failed");
    }
}

try {
    fetchUser(99999);
} catch ($e) {
    echo error_chain_message($e);
    // "fetchUser(99999) failed: no rows returned"
}

17 Module System

Hai loại import: import nạp code vào scope hiện tại. import_as chạy file trong VM riêng, trả về map các symbols được export.
lib/math.gp
<gp>
// Chỉ export những gì cần thiết
export $PI = 3.14159265358979;

export function add($a, $b) {
    return $a + $b + _epsilon();  // có thể gọi private
}

export function circle_area($r) {
    return $PI * $r * $r;
}

export class Vector2D {
    function __construct(public $x, public $y) {}
    function magnitude() { return sqrt($this->x**2 + $this->y**2); }
}

// Private — không export
function _epsilon() { return 1e-10; }
$_config = ["precision" => 15];
main.gp
<gp>
// import_as — isolated module
$math = import_as("lib/math.gp");

echo $math["add"](3, 4);         // 7.0000000001 (+ epsilon)
echo $math["PI"];                 // 3.14159265358979
echo $math["circle_area"](5);    // 78.539...

$v = new $math["Vector2D"](3, 4);
echo $v->magnitude();             // 5.0

// Private không accessible:
// $math["_epsilon"]  → null

// import thông thường — nạp vào scope
import "utils/helpers.gp";
helper_fn();  // accessible trực tiếp

18 Concurrency

gracepl
<gp>
// ── Channel ────────────────────────────────────
$ch = chan_make();    // unbuffered
$ch = chan_make(10); // buffered size=10

$ch <- "hello";      // send (blocking nếu đầy)
$val = <-$ch;        // receive (blocking nếu trống)
chan_close($ch);

// Non-blocking
[$val, $ok] = chan_try_recv($ch);

// ── spawn (goroutine) ─────────────────────────
$results = chan_make(5);
for ($i = 0; $i < 5; $i++) {
    $n = $i;
    spawn {
        $results <- $n * $n;
    };
}

// ── WaitGroup ─────────────────────────────────
$wg = wg_make();
for ($i = 0; $i < 10; $i++) {
    wg_add($wg, 1);
    $idx = $i;
    spawn {
        processItem($idx);
        wg_done($wg);
    };
}
wg_wait($wg);

// ── select ────────────────────────────────────
select {
    case $data <- $ch1:
        echo "Nhận: $data";
    case $ch2 <- "pong":
        echo "Gửi pong";
    default:
        echo "Không ready";
}

19 Context & Cancel

gracepl
<gp>
// Tạo context có thể cancel
$ctx = ctx_make();

spawn {
    ctx_wait_done($ctx);
    echo "Worker dừng\n";
    $done_ch <- true;
};

sleep_ms(2000);        // worker chạy 2 giây
ctx_cancel($ctx);      // báo dừng

// Context với timeout
$ctx = ctx_with_timeout(5000); // 5 giây
spawn {
    ctx_wait_done($ctx);
    if (ctx_cancelled($ctx)) {
        echo "Timeout hoặc cancel\n";
    }
};

// Truyền context qua hàm
function downloadFile($ctx, $url) {
    if (ctx_done($ctx)) return null;
    return http_get($url);
}

20 Mutex & Sync

gracepl
<gp>
global $counter = 0;
$mu = mutex_make();
$wg = wg_make();

// Race-free concurrent counter
for ($i = 0; $i < 100; $i++) {
    wg_add($wg, 1);
    spawn {
        mutex_lock($mu);
        global $counter;
        $counter++;
        mutex_unlock($mu);
        wg_done($wg);
    };
}

wg_wait($wg);
echo $counter; // đúng 100

// mutex_try_lock — non-blocking
if (mutex_try_lock($mu)) {
    // critical section
    mutex_unlock($mu);
} else {
    echo "lock busy";
}

21a Structured Logging

gracepl
<gp>
// JSON format cho ELK/Loki/Datadog
log_format("json");

log_info("request processed", ["user_id" => 42, "latency_ms" => 12]);
// → {"timestamp":"...","level":"INFO","message":"request processed","user_id":42,"latency_ms":12}

log_debug("cache hit", ["key" => "users:42"]);
log_warn("slow query", ["ms" => 1500]);
log_error("connection failed", ["host" => "db.example.com"]);

// Set log level
log_level("warn"); // chì warn + error

// Text mode (development)
log_format("text");
// → [INFO] 2026-03-05 14:30:00 request processed

21b Prometheus Metrics

gracepl
<gp>
// Bật /metrics endpoint
metrics_enable("/metrics");

// Endpoint tųâ trả về Prometheus format:
// gracepl_requests_total 12345
// gracepl_request_errors_total 23
// gracepl_request_duration_ms_bucket{le="10ms"} 8000
// gracepl_request_duration_ms_bucket{le="50ms"} 10000
// gracepl_goroutines 42
// gracepl_memory_alloc_bytes 52428800
// gracepl_uptime_seconds 86400

// Xem active connections
$n = http_active_connections();

21c Circuit Breaker

gracepl
<gp>
// Tąâ circuit breaker: name, max failures, reset timeout (ms)
circuit_breaker("payment-api", 5, 30000);

// Gội function qua circuit breaker
$result = circuit_breaker_call("payment-api", function() {
    return http_post("https://payment.api/charge", ["amount" => 100]);
});

// Circuit mô khi open
if (isset($result["error"])) {
    log_warn("payment circuit open, fallback");
}

// State: "closed" → "open" → "half-open"
$state = circuit_breaker_state("payment-api");

// Reset manual
circuit_breaker_reset("payment-api");

21d Event Bus

gracepl
<gp>
// Ðâng ký handler
event_on("user.created", function($data) {
    log_info("new user", ["email" => $data["email"]]);
    email_send(["to" => $data["email"], "subject" => "Welcome!"]);
});

// Emit event (trâ về số handlers Ðąâ gội)
$count = event_emit("user.created", ["email" => "alice@example.com"]);

// Hųy handlers
event_off("user.created");

21e Cron Scheduler

gracepl
<gp>
// Schedule vói @every syntax
$cleanup = cron("@every 5m", function() {
    db_exec("DELETE FROM sessions WHERE expired_at < NOW()");
});

$health = cron("@every 30s", function() {
    $res = http_get("https://api.example.com/health");
    if (!$res) { log_error("upstream down"); }
});

// Dùng job cų thể
cron_stop($cleanup);

// Dùng tất cẩ
cron_stop_all();

21f Session & Redis

gracepl
<gp>
// Chuyển session sang Redis (scale multi-instance)
session_redis("redis.cluster:6379", "password", "0");

// Sų̉ dų̣ng nhų bình thųồng
session_start();
session_set("user_id", 42);
$uid = session_get("user_id"); // 42
session_flash("message", "Đã lưu thành công");  // one-time message (sau redirect)
$msg = session_flash_get("message");            // đọc và xóa flash
session_destroy();

Database Pool Configuration

gracepl
<gp>
db_connect("user:pass@tcp(host:3306)/mydb");
db_set_timeout(5000);

Redis Configuration

gracepl
<gp>
redis_connect("redis.cluster:6379", "password", "0");
redis_set("key", "value");
$val = redis_get("key");

21g Config Reload

gracepl
<gp>
// Ðâng ký callback khi config reload
config_on_reload(function() {
    global $config;
    $config = json_decode(file_get_contents("config.json"));
    log_info("config reloaded");
});

// Trigger reload
config_reload();

// Unix: kill -SIGHUP <pid> cùng trigger

21 CLI Reference

Lệnh Mô tả
gracepl run <file> Compile & chạy file .gp
gracepl test <dir> Chạy tất cả *_test.gp trong thư mục
gracepl repl Interactive REPL
gracepl lsp Language Server (stdio, VS Code)
gracepl debug <file> DAP debugger (VS Code breakpoints)
gracepl fmt -w <file> Format code (ghi đè file)
gracepl lint <file> Static analysis
gracepl profile <file> Profiler sampling
gracepl build <file> Build standalone binary
gracepl emit <file> Disassemble bytecode
gracepl tokens <file> Dump lexer tokens
gracepl init [name] Tạo grace.json
gracepl install [pkg] Cài package
gracepl remove pkg Gỡ package
gracepl list Danh sách packages
gracepl stop [port] Dừng HTTP server theo port
gracepl restart [port] Restart HTTP server
gracepl --version In phiên bản

22 Testing

example_test.gp
<gp>
// File có tên *_test.gp được test runner phát hiện tự động
import "../lib/test.gp";

describe("Math", function() {
    it("cộng hai số", function() {
        assert_eq(1 + 1, 2);
        assert_eq(10 + 20, 30);
    });

    it("handles edge cases", function() {
        assert_eq(0 + 0, 0);
        assert_eq(-1 + 1, 0);
    });
});

describe("String", function() {
    it("converts to uppercase", function() {
        assert_eq(strtoupper("hello"), "HELLO");
    });

    it("contains substring", function() {
        assert_true(str_contains("gracepl", "grace"));
    });
});

describe("Exceptions", function() {
    it("catches thrown errors", function() {
        assert_throws(function() {
            throw new Error("test error");
        });
    });
});
bash
gracepl test ./examples/
# [PASS] cộng hai số       (0.12ms)
# [PASS] string operations  (0.08ms)
# [PASS] exception được ném (0.05ms)
# [PASS] array operations   (0.09ms)
# ─────────────────────────────────────
# 4/4 passed in 0.34ms

23 Package Manager

bash
gracepl pkg install gracepl/http-utils
gracepl pkg install gracepl/validator
gracepl pkg install gracepl/jwt
gracepl pkg list
# gracepl/http-utils   v1.2.0
# gracepl/validator    v2.0.1
# gracepl/jwt          v1.0.0
gracepl
<gp>
// Package được cài trong vendor/
$validator = import_as("vendor/gracepl/validator/main.gp");

$errors = $validator["validate"]($data, [
    "email"    => "required|email",
    "password" => "required|min:8",
    "age"      => "integer|min:18"
]);

if (count($errors) > 0) {
    http_json($res, ["errors" => $errors], 422);
    return;
}

23b Debugger (DAP — VS Code)

GracePL hỗ trợ Debug Adapter Protocol (DAP), tích hợp trực tiếp với VS Code debugger.

Khởi động

bash
gracepl debug myapp.gp
# Lắng nghe DAP trên stdin/stdout — VS Code kết nối tự động

Cấu hình VS Code (launch.json)

json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "gracepl",
      "request": "launch",
      "name": "Debug GracePL",
      "program": "${file}"
    }
  ]
}

Tính năng

  • Breakpoints (line breakpoints)
  • Step Over / Step Into / Step Out
  • Xem locals, globals, upvalues
  • Call stack
  • Debug Console (eval expression)

24 HTTP & Web

gracepl
<gp>
// ── HTTP Server ────────────────────────────────
http_handle("/", function($req) {
    http_json(["message" => "Hello from GracePL!"]);
});

// Route động: $req["params"]["id"] — lấy path segment
http_handle("/users/:id", function($req) {
    $id = $req["params"]["id"];
    $user = db_query_row("SELECT * FROM users WHERE id = ?", [$id]);
    if (!$user) { return http_json(["error" => "Not found"], 404); }
    http_json($user);
});

// Query string: $req["query"]["name"] — lấy ?name=Alice
http_handle("/search", function($req) {
    $q = isset($req["query"]["q"]) ? $req["query"]["q"] : "";
    http_json(["query" => $q]);
});

// Middleware stack — gọi trước http_serve()
http_request_id();                           // inject X-Request-Id header
http_panic_recover();                        // catch panic → 500 JSON
http_cors_whitelist(["https://myapp.com"]);  // CORS cho các origin được phép
http_rate_limit(100, 60);                    // 100 req/phút mỗi IP
http_security_headers();                     // X-Frame-Options, CSP, HSTS…
http_gzip();                                 // nén gzip tự động
metrics_enable("/metrics");                  // Prometheus /metrics endpoint
http_health("/health");                      // GET /health → {"status":"ok"}
log_format("json");                          // log dưới dạng JSON
http_static("public", "/static");            // serve file tĩnh
http_use(function($req) {                    // custom middleware
    return true; // false để chặn request
});

http_serve(":8080");

Request object ($req)

KeyMô tảVí dụ
$req["params"]Path segments dynamic (/users/:id)$req["params"]["id"]
$req["query"]Query string (?name=Alice&page=2)$req["query"]["name"]
$req["body"]Request body (string). Form/multipart → body đã parsejson_decode($req["body"])
$req["files"]Upload: $req["files"][fieldName] = array of {name, size, temp_path, content_type}
$req["method"]HTTP method"GET", "POST"
$req["headers"]Request headers (map)$req["headers"]["authorization"]
$req["ip"]Client IP"127.0.0.1"
⚠️ Route wildcards không được hỗ trợ: /* là path literal, không phải wildcard. Dùng :param hoặc {param} cho segment động.
  ✅ /news/:slug — đúng
  ❌ /news/* — không match được gì
⚠️ Kiểm tra key tồn tại: Trong GracePL, null != false trả về true — không dùng $params["x"] != false để kiểm tra key có tồn tại. Dùng isset($params["x"]).

HTTP Middleware & Utility

HàmMô tả
http_cors($origin)Bật CORS — nhận string, "*" hoặc một origin cụ thể
http_cors_whitelist($origins)CORS whitelist — nhận array các origin được phép
http_rate_limit($reqs, $window_sec)Giới hạn $reqs request/IP trong $window_sec giây
http_security_headers([$csp])Thêm X-Frame-Options, X-Content-Type-Options, CSP, HSTS, Referrer-Policy
http_gzip()Bật nén gzip tự động cho response
http_health($path)Tạo health-check endpoint: GET $path → {"status":"ok"}
http_static($dir [, $prefix])Serve file tĩnh từ thư mục $dir tại URL $prefix
http_use($fn)Custom GracePL middleware — $fn($req) trả về true (tiếp tục) hoặc false (chặn)
http_redirect($url [, $code])Redirect → mặc định 302
http_redirect_back([$fallback])Redirect về Referer; không có thì dùng $fallback (mặc định /)
http_request_id([$header])Inject X-Request-Id vào request & response (tạo mới nếu không có)
http_panic_recover()Bắt panic trong handler → trả về 500 JSON thay vì crash server
http_active_connections()Số kết nối HTTP đang active → int
gracepl — WebSocket
<gp>
// ── WebSocket ──────────────────────────────────
// Giới hạn dung lượng nhận tối đa mỗi tin nhắn/frame (vd: 10MB)
ws_set_read_limit(10485760);

listen("/chat") {
    on("connect", function($conn) {
        ws_room_join("general");
    });
    on("message", function($data) {
        // Broadcast string hoặc binary raw
        ws_room_broadcast("general", $data["text"]);
    });
}

// ── HTTP Client ────────────────────────────────
$res = http_get("https://api.example.com/data");
$post = http_post("https://api.example.com/users", [
    "headers" => ["Content-Type" => "application/json"],
    "body"    => json_encode(["name" => "Alice"])
]);

WebSocket Room Helpers

HàmMô tả
ws_room_join($room)Thêm kết nối WS hiện tại vào room
ws_room_leave($room)Rời room
ws_room_broadcast($room, $msg)Gửi text tới tất cả member trong room
ws_room_broadcast_binary($room, $bytes)Gửi binary tới tất cả member trong room
ws_room_members($room)Trả về array conn ID của các member
ws_rooms()Trả về danh sách tất cả room đang active
ws_conn_id()Lấy ID của kết nối WS hiện tại (trong handler)
ws_ping()Gửi ping frame tới kết nối hiện tại
ws_set_read_limit($bytes)Giới hạn kích thước frame nhận tối đa

24b Template Engine

GracePL có template engine tích hợp hỗ trợ variable substitution, conditionals, loops và includes.

Hiệu năng: Đi kèm cơ chế in-memory caching tự động (kiểm tra theo ModTime của file), giúp tăng tốc script render và loại bỏ thao tác đọc đĩa không cần thiết.

Cú pháp template

Cú pháp Mô tả
{{key}} Thay bằng giá trị biến — tự động HTML-escape (hỗ trợ cả {{$key}})
{{key | raw}} Output HTML thô không escape — dùng khi biến chứa HTML markup (card list, content block…)
{{if key}} ... {{endif}} Conditional block (truthy); hỗ trợ lồng nhau
{{if !key}} ... {{endif}} Negated conditional
{{if key}} ... {{else}} ... {{endif}} Conditional với else branch
{{key | slice:start:end}} / {{key | upper}} / {{key | lower}} Filter: cắt chuỗi, chuyển hoa/thường
{{key | default:"fallback"}} / {{key | length}} Filter: giá trị mặc định, độ dài
{{foreach items as item}} ... {{end}} Loop qua array/map
{{include "path"}} Inline file template khác (dùng chung data)

Hàm render

Hàm Mô tả
render($file, $vars) Render template từ file với biến
render_string($tmpl, $vars) Render template từ chuỗi
include($file) Đọc file thuần (không thay biến)

Ví dụ: Layout với include

templates/base.html
<!DOCTYPE html>
<html>
<head><title>{{title}} — MyApp</title></head>
<body>
    {{include "templates/header.html"}}
    <main>{{content}}</main>
    {{include "templates/footer.html"}}
</body>
</html>

Ví dụ: Conditional + Loop

templates/list.html
<h1>{{page_title}}</h1>
{{if has_items}}
<ul>
    {{foreach items as item}}
    <li>{{item}}</li>
    {{end}}
</ul>
{{else}}
<p>Không có item nào.</p>
{{endif}}

Pattern: Render nested objects

gracepl
<gp>
$posts = [
    ["title" => "Post 1", "date" => "2026-01-15"],
    ["title" => "Post 2", "date" => "2026-01-20"]
];

$cards = "";
foreach ($posts as $post) {
    $cards .= render("templates/card.html", $post);
}

$html = render("templates/list.html", [
    "page_title" => "Blog",
    "cards" => $cards
]);
Tip: Khi mỗi item là map có nhiều fields (title, date, url...), render từng item riêng rồi truyền HTML vào template cha qua biến. Đây là pattern khuyên dùng cho nested data.
⚠️ HTML Escaping: Mặc định {{var}} sẽ escape HTML (<, >, &…). Nếu biến chứa HTML markup (ví dụ: card list, content bài viết), phải dùng {{var | raw}} — nếu không HTML sẽ hiển thị dưới dạng text thay vì được render.

24c Biến Môi Trường

GracePL cung cấp env_load()env() để quản lý cấu hình qua file .env — không hardcode secret trong source code.

⚠️ Quan trọng: Phải gọi env_load(".env") trước khi dùng env(). Nếu không, env() chỉ đọc từ OS environment variables.

File .env

.env
# Cổng phải có dấu ":" ở đầu
APP_PORT=:3001
DB_HOST=localhost
DB_NAME=mydb
DB_USER=root
DB_PASS=secret
ALLOWED_ORIGIN=https://yourdomain.com

Đọc biến môi trường

gracepl
<gp>
// Nạp file .env (relative tới thư mục của script — không phải cwd)
env_load(".env");

// Đọc biến — tham số 2 là giá trị mặc định nếu key không tồn tại
$port   = env("APP_PORT", ":8000");
$dbHost = env("DB_HOST",  "localhost");
$debug  = env("DEBUG",    "false");

// Khởi động server
http_serve($port);

Lưu ý về cổng (port)

Giá trị APP_PORTKết quả
APP_PORT=:3001✅ Đúng — listen trên port 3001
APP_PORT=3001❌ Sai — thiếu :, server không start được

Bảo mật

  • Luôn thêm .env vào .gitignore — không commit secret lên repo
  • Dùng .env.example (không có giá trị thật) để hướng dẫn team
  • Không hardcode API key, database password trong source code

24d HTTPS / TLS

Chạy server với SSL/TLS, hỗ trợ TLS 1.2+ và các cipher suite an toàn. Cần file certificate.

gracepl
<gp>
// http_serve_tls(addr, cert_file, key_file)
// TLS 1.2+ với AES-GCM và ChaCha20-Poly1305

http_handle("/", function($req) {
    return http_json(["status" => "ok"]);
});

// Tự ký (development)
// openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

http_serve_tls(":443", "cert.pem", "key.pem");
// hoặc port khác:
// http_serve_tls(":8443", "certs/cert.pem", "certs/key.pem");
HàmTham sốMô tả
http_serve_tls($addr, $cert, $key)addr=":443", cert/key=PEM file pathKhởi động HTTPS server với graceful shutdown
http_serve($addr)addr=":8080"HTTP thường — dùng cho development hoặc sau reverse proxy
💡 Production: Dùng Let's Encrypt + Certbot để có cert miễn phí. Hoặc đặt Nginx/Caddy trước làm reverse proxy để terminate TLS, GracePL chạy HTTP nội bộ.

24e HTTP Server Config

Tinh chỉnh timeout, request body limit và access log của HTTP server. Phải gọi trước http_serve().

gracepl
<gp>
// http_server_config(key, value)

http_server_config("read_timeout",  30);   // giây — mặc định 30s
http_server_config("write_timeout", 30);   // giây — mặc định 30s
http_server_config("idle_timeout",  120);  // giây — mặc định 120s
http_server_config("body_limit",    5242880); // bytes — mặc định 10MB (10<<20)
http_server_config("access_log",    false);   // tắt access log

http_serve(":8080");
KeyKiểuMặc địnhMô tả
read_timeoutint (giây)30Thời gian tối đa đọc toàn bộ request
write_timeoutint (giây)30Thời gian tối đa ghi response
idle_timeoutint (giây)120Thời gian keep-alive connection chờ request tiếp
body_limitint (bytes)10485760Kích thước tối đa request body
access_logbooltrueBật/tắt access log cho mỗi request

24f CSRF Protection

Bảo vệ form POST khỏi Cross-Site Request Forgery. Token có chữ ký HMAC-SHA256, hết hạn sau 2 giờ.

gracepl
<gp>
// Bước 1: Khởi tạo CSRF (trước khi serve)
csrf_init("secret-key-của-bạn"); // nếu bỏ qua → tự sinh random secret

// Bước 2: Sinh token cho form GET
http_handle("/form", function($req) {
    $token = csrf_token();
    return render("templates/form.html", ["csrf_token" => $token]);
});

// Bước 3: Kiểm tra token khi POST
http_handle("POST", "/submit", function($req) {
    $token = $req["body"]["_csrf"] ?? $req["headers"]["x-csrf-token"] ?? "";
    if (!csrf_verify($token)) {
        return http_status(403, "CSRF token không hợp lệ");
    }
    // xử lý form...
    return http_redirect("/success");
});
templates/form.html
<form method="POST" action="/submit">
  <input type="hidden" name="_csrf" value="{{csrf_token | raw}}">
  <input type="text" name="name" placeholder="Tên">
  <button type="submit">Gửi</button>
</form>
HàmMô tả
csrf_init($secret?)Khởi tạo CSRF; nếu bỏ secret → tự sinh an toàn
csrf_token()Sinh token mới (ký HMAC-SHA256, hiệu lực 2 giờ)
csrf_verify($token)Kiểm tra token hợp lệ và chưa hết hạn → bool

24g HTTP Route Helpers

Sugar functions để đăng ký route theo method cụ thể — ngắn hơn http_handle().

gracepl
<gp>
// Tương đương http_handle("GET", "/path", $fn)
http_route_get("/api/users", function($req) {
    return http_json(db_query("SELECT id, name FROM users"));
});

http_route_post("/api/users", function($req) {
    $data = json_decode($req["body"]);
    db_exec("INSERT INTO users (name) VALUES (?)", [$data["name"]]);
    return http_json(["status" => "created"], 201);
});

http_route_put("/api/users/:id", function($req) {
    $id = $req["params"]["id"];
    $data = json_decode($req["body"]);
    db_exec("UPDATE users SET name = ? WHERE id = ?", [$data["name"], $id]);
    return http_json(["updated" => true]);
});

http_route_delete("/api/users/:id", function($req) {
    $id = $req["params"]["id"];
    db_exec("DELETE FROM users WHERE id = ?", [$id]);
    return http_json(["deleted" => true]);
});

http_serve(":8080");
HàmTương đương
http_route_get($path, $fn)http_handle("GET", $path, $fn)
http_route_post($path, $fn)http_handle("POST", $path, $fn)
http_route_put($path, $fn)http_handle("PUT", $path, $fn)
http_route_delete($path, $fn)http_handle("DELETE", $path, $fn)

25 Thư viện: String

Hàm Mô tả
strlen($s) Độ dài chuỗi (bytes)
strtoupper/lower($s) Chuyển hoa/thường
substr($s, $start, $len) Lấy chuỗi con
str_replace($s, $r, $h) Thay thế chuỗi
strpos($h, $n) Vị trí chuỗi (false nếu không có)
trim($s) Xóa khoảng trắng đầu/cuối
explode($d, $s) Split thành array
implode($d, $a) Join array thành string
str_contains($s, $n) Kiểm tra chứa chuỗi con
str_pad($s, $n, $p, $t) Pad chuỗi
sprintf($fmt, ...) Format string
preg_match($p, $s, &$m) Regex match
preg_replace($p, $r, $s) Regex replace
md5/sha1/sha256($s) Hash chuỗi
base64_encode/decode($s) Base64
urlencode/decode($s) URL encode/decode
htmlspecialchars($s) / htmlentities($s) / html_decode($s) Escape / decode HTML
addslashes($s) / strip_tags($s) Escape cho SQL / xóa thẻ HTML
markdown_to_html($s) Chuyển Markdown sang HTML
slugify($s [, $lang]) Chuỗi URL-friendly (Unicode)

26 Thư viện: Array

Hàm Mô tả
count($a) Số phần tử
array_push($a, $v) Thêm vào cuối — trả về số phần tử mới, không trả về mảng. Không viết $a = array_push($a, $v)
array_pop($a) Xóa và trả về phần tử cuối
array_shift($a) Xóa và trả về phần tử đầu
array_unshift($a, $v) Thêm vào đầu
array_map($fn, $a) Map qua mỗi phần tử
array_filter($a, $fn) Lọc phần tử
array_reduce($a, $fn, $init) Reduce
array_merge($a, $b) Gộp hai mảng
array_unique($a) Xóa trùng
array_keys($m) Lấy tất cả keys
array_values($a) Lấy tất cả values
array_chunk($a, $n) Chia thành chunks
in_array($v, $a) Kiểm tra phần tử tồn tại
sort/rsort($a) Sắp xếp tăng/giảm
usort($a, $fn) Sắp xếp theo hàm so sánh
array_sum($a) Tổng các phần tử
array_combine($keys, $vals) Tạo map từ 2 arrays
array_flip($a) Đổi key↔value
array_slice($a, $off, $len) Cắt mảng
array_splice($a, $off, $n, $r) Xóa và thay thế

27 Thư viện: Math

Hàm / Hằng Mô tả
M_PI π ≈ 3.14159…
M_E e ≈ 2.71828…
abs($n) Giá trị tuyệt đối
ceil($n) / floor($n) Làm tròn lên/xuống
round($n, $p) Làm tròn p chữ số thập phân
sqrt($n) Căn bậc hai
pow($b, $e) Lũy thừa
log($n) / log10($n) Logarithm tự nhiên / cơ số 10
sin/cos/tan($r) Lượng giác (radian)
asin/acos/atan($n) Lượng giác ngược
atan2($y, $x) Arctangent 2 chiều
min($a, $b, …) Giá trị nhỏ nhất
max($a, $b, …) Giá trị lớn nhất
rand($min, $max) Số ngẫu nhiên nguyên
intdiv($a, $b) Chia nguyên
fmod($a, $b) Chia lấy dư float
number_format($n, $d) Format số với dấu phẩy
is_nan($n) / is_inf($n) Kiểm tra NaN / Infinity

28 Thư viện: File I/O

gracepl
<gp>
// Đọc / ghi
$content = file_get_contents("data.txt");
file_put_contents("out.txt", $content);
file_put_contents("log.txt", "Line\n", FILE_APPEND);

// Dòng
$lines = file("data.txt");  // array các dòng
foreach ($lines as $line) { echo trim($line); }

// Kiểm tra
file_exists("path")
is_file("path")
is_dir("path")

// Thư mục
mkdir("new_dir", 0755, true);   // recursive
rmdir("dir");
scandir("dir");     // [".", "..", "file.txt", ...]

// Copy / Move / Delete
copy("src", "dst");
rename("old", "new");
unlink("file.txt");

// Đường dẫn
basename("/path/to/file.txt");   // "file.txt"
dirname("/path/to/file.txt");    // "/path/to"
realpath("../relative");
pathinfo("file.txt.gz");         // ["extension" => "gz", ...]

// File size / permissions
filesize("file.txt");
filemtime("file.txt");  // timestamp sửa đổi
chmod("file.txt", 0644);

29 Thư viện: JSON

gracepl
<gp>
$data = ["name" => "Alice", "age" => 30, "tags" => ["go", "php"]];

// Encode
$json = json_encode($data);
// {"name":"Alice","age":30,"tags":["go","php"]}

$pretty = json_encode($data, JSON_PRETTY_PRINT);

// Decode → map/array
$map = json_decode($json);
echo $map["name"];   // Alice
echo $map["tags"][0]; // go


// Từ file
$config = json_decode(file_get_contents("config.json"));
file_put_contents("output.json", json_encode($result, JSON_PRETTY_PRINT));

30 Thư viện: HTTP Client

Gọi API bên ngoài bằng các hàm HTTP client tích hợp sẵn.

HàmMô tả
http_get($url, $headers?)GET request, trả về response body
http_post($url, $body, $headers?)POST request
http_put($url, $body, $headers?)PUT request
http_delete($url, $headers?)DELETE request
http_request($method, $url, $body?, $headers?)Generic HTTP request tùy chỉnh
http_download($url, $path)Tải file về đĩa
gracepl
<gp>
// GET request
$body = http_get("https://api.example.com/users");
$data = json_decode($body);
echo $data[0]["name"];

// POST với JSON body
$token = "secret";
$resp = http_post(
    "https://api.example.com/users",
    json_encode(["name" => "Alice", "email" => "alice@example.com"]),
    ["Content-Type" => "application/json", "Authorization" => "Bearer $token"]
);
$created = json_decode($resp);
echo "Created user #" . $created["id"];

// PUT — cập nhật resource
http_put("https://api.example.com/users/1",
    json_encode(["name" => "Alice Updated"]),
    ["Content-Type" => "application/json"]);

// DELETE
http_delete("https://api.example.com/users/1");

// Generic request
$resp = http_request("PATCH", "https://api.example.com/users/1",
    json_encode(["active" => true]),
    ["Content-Type" => "application/json"]);

// Download file về đĩa
http_download("https://example.com/report.pdf", "downloads/report.pdf");
echo "Tải xong!";

31 Thư viện: Database

gracepl
<gp>
// Kết nối
// Kết nối (MySQL, PostgreSQL, SQLite)
db_connect("user:pass@tcp(localhost:3306)/mydb");
// db_connect("postgres://user:pass@localhost/mydb");
// db_connect("sqlite://./data.db");

// Query — trả về array of maps
$rows = db_query("SELECT id, name FROM users WHERE active = ?", [1]);
foreach ($rows as $row) {
    echo "{$row['id']}: {$row['name']}\n";
}

// Single row
$user = db_query_row("SELECT * FROM users WHERE id = ?", [42]);

// Execute (INSERT, UPDATE, DELETE, DDL)
db_exec("INSERT INTO users (name, email) VALUES (?, ?)", ["Alice", "a@b.c"]);
db_exec("UPDATE users SET name = ? WHERE id = ?", ["Alice Updated", 42]);
db_exec("DELETE FROM users WHERE id = ?", [42]);

// Transaction
$tx = db_begin();
db_tx_exec($tx, "UPDATE accounts SET balance = balance - 100 WHERE id = ?", [1]);
db_tx_exec($tx, "UPDATE accounts SET balance = balance + 100 WHERE id = ?", [2]);
db_commit($tx);

// Prepared statements
$stmt = db_prepare("INSERT INTO logs (msg) VALUES (?)");
for ($i = 0; $i < 1000; $i++) {
    db_stmt_exec($stmt, ["log message $i"]);
}
db_stmt_close($stmt);

// Timeout + close
db_set_timeout(5000);
db_close();

32 Thư viện: Channel & Sync

Hàm Mô tả
chan_make($size?) Tạo channel (size=64 nếu bỏ)
chan_send($ch, $v) Gửi giá trị
chan_recv($ch) Nhận giá trị (blocking)
chan_try_recv($ch) Nhận không blocking → [$v, $ok]
chan_close($ch) Đóng channel
chan_len($ch) Số items đang đợi trong buffer
wg_make() Tạo WaitGroup
wg_add($wg, $n) Thêm n vào counter
wg_done($wg) Trừ 1 từ counter
wg_wait($wg) Chờ counter về 0
mutex_make() Tạo Mutex
mutex_lock($m) Lock (blocking)
mutex_unlock($m) Unlock
mutex_try_lock($m) Try lock → bool
ctx_make() Tạo context
ctx_cancel($ctx) Cancel context
ctx_with_timeout($ms) Context với timeout (ms)
ctx_done($ctx) Kiểm tra đã done?
ctx_wait_done($ctx) Block tới khi done
sleep_ms($ms) Ngủ $ms mili-giây
go_run($fn, $args) Chạy callable trong goroutine

33 Thư viện: Crypto & Security

Password

HàmMô tả
password_hash($pwd [, $algo, $cost])Bcrypt hash — lưu DB, không reversible. cost mặc định 10
password_verify($pwd, $hash)Kiểm tra password vs bcrypt hash → bool
random_bytes($n)Hex string $n bytes ngẫu nhiên crypto/rand (mặc định 32, max 4096)

Hashing

HàmMô tả
md5($s)MD5 hex — chỉ dùng cho checksum, không dùng cho auth
sha1($s)SHA1 hex
sha256($s)SHA-256 hex
hash_hmac($algo, $data, $key)HMAC-SHA256 hex — algo: "sha256"

AES Encryption (AES-256-GCM)

gracepl
<gp>
$key = "secret-key-của-bạn"; // tự SHA-256 thành 32 bytes nội bộ

// Mã hóa → base64(nonce[12] + ciphertext + tag[16])
$cipher = aes_encrypt("thông tin nhạy cảm", $key);
echo $cipher; // base64 string

// Giải mã
$plain = aes_decrypt($cipher, $key);
echo $plain; // "thông tin nhạy cảm"

// Dùng key 32-byte raw (không qua SHA-256 nội bộ)
$rawKey = bytes_from_hex("0123456789abcdef...");
$cipher2 = aes_encrypt_key("data", $rawKey);
$plain2  = aes_decrypt_key($cipher2, $rawKey);
HàmMô tả
aes_encrypt($plain, $key [, $raw])AES-256-GCM encrypt → base64. $raw=true → KBytes
aes_decrypt($cipher_b64, $key [, $raw])Giải mã base64 → string plaintext
aes_encrypt_key($plain, $bytes_key)Encrypt với KBytes key (phải đúng 16/24/32 bytes)
aes_decrypt_key($cipher, $bytes_key)Decrypt với KBytes key

RSA Asymmetric Encryption

gracepl
<gp>
// Sinh cặp key RSA
$keys = rsa_generate(2048); // {"private": "-----BEGIN...", "public": "-----BEGIN..."}
$priv = $keys["private"];
$pub  = $keys["public"];

// Ký dữ liệu (SHA-256 hoặc SHA-512)
$sig = rsa_sign("payload data", $priv, "sha256");

// Xác minh chữ ký
$ok = rsa_verify("payload data", $sig, $pub, "sha256");

// Mã hóa bằng public key (RSA-OAEP)
$enc = rsa_encrypt("secret msg", $pub);
$dec = rsa_decrypt($enc, $priv);
HàmMô tả
rsa_generate($bits?)Sinh RSA key pair → {private, public} PEM strings. bits mặc định 2048
rsa_sign($data, $priv_pem [, $algo])Ký → base64 signature. algo: "sha256" (mặc định), "sha512"
rsa_verify($data, $sig_b64, $pub_pem [, $algo])Xác minh chữ ký → bool
rsa_encrypt($plain, $pub_pem)RSA-OAEP encrypt → base64
rsa_decrypt($cipher_b64, $priv_pem)RSA-OAEP decrypt → plaintext

34 Thư viện: Process Management

Chạy lệnh hệ thống, script ngoài, hoặc tool deploy từ GracePL.

gracepl
<gp>
// proc_exec(cmd [, args, cwd, stdin]) → {stdout, exit_code}
// Blocking — chờ process kết thúc
$result = proc_exec("git", ["log", "--oneline", "-5"], "/app");
echo $result["stdout"];     // output của git
echo $result["exit_code"];  // 0 = thành công

// shell_exec(cmd) — chạy qua shell (sh -c / cmd /C), trả về output string
$files = shell_exec("ls -la /var/log");

// proc_exec_async — non-blocking, trả về resource handle
$handle = proc_exec_async("npm", ["run", "build"], "/app/frontend");
// ... làm việc khác trong lúc build chạy ...
$res = proc_wait($handle); // chờ kết thúc
echo "Build exit: " . $res["exit_code"];

// Với stdin (pipe input)
$out = proc_exec("grep", ["error"], "", "line1\nERROR: fail\nline3");
echo $out["stdout"]; // "ERROR: fail"
HàmMô tả
proc_exec($cmd [, $args, $cwd, $stdin])Chạy process blocking → {stdout, exit_code}
proc_exec_async($cmd [, $args, $cwd, $stdin])Chạy async → resource handle
proc_wait($handle)Chờ async process → {stdout, exit_code}
shell_exec($cmd)Chạy qua shell → output string (như `cmd` trong PHP)
⚠️ Bảo mật: Không truyền user input trực tiếp vào shell_exec() — nguy cơ command injection. Dùng proc_exec() với args array để tham số được escape tự động.

35 Thư viện: TCP / UDP / DNS

Raw network programming — xây dựng proxy, custom protocol server, health check, DNS lookup.

TCP Client

gracepl — TCP client
<gp>
// Kết nối TCP
$conn = tcp_connect("example.com", 80, 5000); // timeout 5000ms
if ($conn == false) { echo "Kết nối thất bại\n"; }

// Gửi / nhận
tcp_write($conn, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
$resp = tcp_read($conn, 4096);
echo $resp;

echo tcp_remote_addr($conn); // "93.184.216.34:80"
echo tcp_local_addr($conn);  // "192.168.1.5:54321"
tcp_set_deadline($conn, 3000); // timeout 3s cho lần đọc/ghi tiếp
tcp_close($conn);

TCP Server

gracepl — TCP server
<gp>
// Cách 1: tcp_serve (blocking, xử lý từng conn trong goroutine)
tcp_serve(9000, function($conn) {
    $data = tcp_read($conn, 1024);
    tcp_write($conn, "Echo: " . $data);
    tcp_close($conn);
});

// Cách 2: Manual accept loop
$server = tcp_listen(9000);
echo "Listening: " . tcp_server_addr($server) . "\n";
while (true) {
    $conn = tcp_accept($server);
    spawn {
        $msg = tcp_read($conn, 1024);
        tcp_write($conn, strtoupper($msg));
        tcp_close($conn);
    }
}
tcp_server_close($server);

UDP

gracepl — UDP
<gp>
// UDP gửi (fire-and-forget)
udp_send("logger.internal", 5140, "log message");

// UDP server
$sock = udp_listen(8125);
while (true) {
    [$data, $addr] = udp_recv($sock, 512);
    echo "From $addr: $data\n";
    udp_reply($sock, "ACK", $addr); // phản hồi về địa chỉ gốc
}
udp_server_close($sock);

DNS

gracepl — DNS
<gp>
$ips = dns_lookup("github.com");
// ["140.82.121.4", "140.82.121.3"]

$mxs = dns_lookup_mx("gmail.com");
// [{"host": "gmail-smtp-in.l.google.com.", "pref": 5}, ...]
foreach ($mxs as $mx) {
    echo $mx["host"] . " (priority: " . $mx["pref"] . ")\n";
}
HàmMô tả
tcp_connect($host, $port [, $timeout_ms])Kết nối TCP → conn resource hoặc false
tcp_write($conn, $data)Gửi data → số bytes đã ghi hoặc false
tcp_read($conn [, $size])Đọc data → string hoặc false khi đóng
tcp_close($conn)Đóng TCP connection
tcp_set_deadline($conn, $ms)Đặt deadline cho đọc/ghi tiếp theo
tcp_remote_addr($conn)"host:port" của remote
tcp_local_addr($conn)"host:port" của local
tcp_listen($port [, $host])Tạo TCP server → server resource
tcp_accept($server)Chờ và chấp nhận conn mới (blocking)
tcp_serve($port, $fn [, $host])TCP server vòng lặp — gọi $fn($conn) trong goroutine
tcp_server_close($server)Đóng server
tcp_server_addr($server)"host:port" server đang lắng nghe
udp_send($host, $port, $data)Gửi UDP datagram
udp_listen($port [, $host])Tạo UDP server → sock resource
udp_recv($sock [, $size])Nhận datagram → [$data, $addr]
udp_reply($sock, $data, $addr)Gửi về địa chỉ đã nhận ($addr từ udp_recv)
udp_server_close($sock)Đóng UDP server
dns_lookup($host)Resolve hostname → array IP strings hoặc false
dns_lookup_mx($domain)Lấy MX records → array {host, pref} hoặc false

36 Thư viện: File Watch

Theo dõi thay đổi file/thư mục theo thời gian thực — dùng để hot reload config, tự build, phát hiện upload.

gracepl
<gp>
// Theo dõi 1 file
$w = file_watch("config.json", function($event) {
    echo "File thay đổi: " . $event["path"] . " op: " . $event["op"] . "\n";
    // op: "create" | "write" | "remove" | "rename" | "chmod"
});

// Theo dõi thư mục đệ quy
$w2 = file_watch("templates/", function($event) {
    if ($event["op"] == "write") {
        echo "Template " . $event["path"] . " đã cập nhật\n";
    }
}, ["recursive" => true]);

// Thêm/bỏ path từ watcher đang chạy
file_watch_add($w2, "static/");
file_watch_remove($w2, "templates/old/");

// Dừng theo dõi
sleep(60);
file_watch_stop($w);
file_watch_stop($w2);
HàmMô tả
file_watch($path, $fn [, $opts])Bắt đầu theo dõi. opts: ["recursive" => true] → watcher resource
file_watch_stop($watcher)Dừng và giải phóng watcher
file_watch_add($watcher, $path)Thêm path mới vào watcher đang chạy
file_watch_remove($watcher, $path)Bỏ path khỏi watcher

Callback nhận map: {"path": "...", "op": "create|write|remove|rename|chmod"}

37 Thư viện: In-memory Cache

Cache nhanh trong bộ nhớ với TTL tự động. Không cần Redis — phù hợp cho single-process app.

gracepl
<gp>
// Lưu với TTL 60 giây
cache_set("user:42", ["name" => "Alice", "role" => "admin"], 60);

// Lấy — null nếu hết hạn hoặc không có
$user = cache_get("user:42");
if ($user != null) {
    echo "Cache hit: " . $user["name"];
} else {
    // load từ DB và cache lại
    $user = db_query_row("SELECT * FROM users WHERE id = 42");
    cache_set("user:42", $user, 300); // cache 5 phút
}

// Xóa key
cache_delete("user:42");

// Xóa toàn bộ cache
cache_flush();
HàmMô tả
cache_set($key, $value [, $ttl_sec])Lưu vào cache. TTL tính bằng giây, mặc định không hết hạn
cache_get($key)Lấy giá trị → null nếu không có hoặc hết hạn
cache_delete($key)Xóa key khỏi cache
cache_flush()Xóa toàn bộ cache

38 Thư viện: Profiling

Đo thời gian thực thi từng function trong VM — giúp tìm bottleneck.

gracepl
<gp>
prof_start(); // bật profiler

// ... chạy code cần đo ...
$data = db_query("SELECT * FROM products");
foreach ($data as $item) {
    process_item($item);
}

prof_stop(); // tắt profiler

// In báo cáo: function name, call count, total time
echo prof_report();
HàmMô tả
prof_start()Bật profiling VM — theo dõi tất cả function calls
prof_stop()Tắt profiling
prof_report()Trả về string báo cáo: function, call count, thời gian tổng

39 Thư viện: Error Chaining

Tạo và bọc lỗi có nguyên nhân (cause chain) — giống Go errors.Wrap hoặc PHP's previous exception.

gracepl
<gp>
// Tạo lỗi gốc
$dbErr = error_create("Kết nối DB thất bại", 500);

// Bọc lỗi với context
$svcErr = error_wrap($dbErr, "Không thể nạp dữ liệu người dùng", 503);
$apiErr = error_wrap($svcErr, "Request thất bại");

// Kiểm tra lỗi
if (is_error($apiErr)) {
    // Lấy toàn bộ chuỗi thông báo
    echo error_chain_message($apiErr);
    // → "Request thất bại: caused by: Không thể nạp dữ liệu người dùng: caused by: Kết nối DB thất bại"

    // Lấy nguyên nhân gốc
    $root = error_cause(error_cause($apiErr));
    echo $root["message"]; // "Kết nối DB thất bại"
    echo $root["code"];    // 500
}
HàmMô tả
error_create($msg [, $code])Tạo error map: {error:true, message, code}
error_wrap($cause, $msg [, $code])Bọc lỗi với context mới — lưu nguyên nhân gốc vào cause
error_cause($err)Lấy nguyên nhân trực tiếp của lỗi đã wrap
error_chain_message($err)Chuỗi thông báo toàn bộ chain: "msg1: caused by: msg2: ..."
is_error($v)Kiểm tra $v có phải error map không → bool

40 Thư viện: Binary / Bytes

Xử lý dữ liệu nhị phân — binary protocol, mã hóa/giải mã, file binary, pack/unpack.

Bytes (KBytes type)

gracepl
<gp>
// Tạo bytes
$b = bytes_from_string("Hello");   // string → KBytes
$b2 = bytes_from_hex("deadbeef");  // hex string → KBytes

// Thao tác
echo bytes_length($b);         // 5
echo bytes_get($b, 0);         // 72 (ASCII 'H')
bytes_set($b, 0, 104);         // sửa byte đầu thành 'h'
$slice = bytes_slice($b, 1, 3); // bytes[1..3)
$joined = bytes_concat($b, $b2);

// Chuyển đổi
echo bytes_to_string($b);      // "hello"
echo bytes_to_hex($b);         // "68656c6c6f"

// File binary
$img = file_read_bytes("photo.jpg");
echo bytes_length($img);       // kích thước file
file_write_bytes("copy.jpg", $img);

Pack / Unpack (PHP-compatible)

gracepl — pack/unpack
<gp>
// pack(format, ...values) → binary string
// Format codes: N=uint32 big-endian, n=uint16 big-endian, C=uint8, A=string
$header = pack("NnC", 1000, 42, 7);

// unpack — positional
$vals = unpack("NnC", $header);
echo $vals[0]; // 1000 (uint32)
echo $vals[1]; // 42   (uint16)
echo $vals[2]; // 7    (uint8)

// unpack — named (PHP style: "N1len/n1flags")
$data = unpack("N1length/n1flags/C1version", $header);
echo $data["length"]; // 1000
echo $data["flags"];  // 42
HàmMô tả
bytes_from_string($s)string → KBytes
bytes_to_string($b)KBytes → string
bytes_length($b)Số bytes
bytes_get($b, $i)Lấy byte tại index $i → int
bytes_set($b, $i, $v)Sửa byte tại index
bytes_slice($b, $start, $end)Cắt [start, end)
bytes_concat($a, $b)Nối hai KBytes
bytes_to_hex($b)KBytes → hex string
bytes_from_hex($hex)Hex string → KBytes
file_read_bytes($path)Đọc file → KBytes
file_write_bytes($path, $b)Ghi KBytes vào file
pack($fmt, ...)Đóng gói values thành binary string (PHP format)
unpack($fmt, $data)Giải gói binary → array hoặc map (named format)