APIs and Interfaces
Overview
APIs (Application Programming Interfaces) and interfaces are key concepts in PHP development. This chapter covers object-oriented interfaces, interacting with Web APIs, creating RESTful services, and consuming external APIs. Understanding these concepts is essential for building modern, interconnected applications.
Object-Oriented Interfaces
Basic Interface Definition
php
<?php
// Interface definition
interface PaymentProcessorInterface {
public function processPayment($amount, $currency);
public function refundPayment($transactionId);
public function getTransactionStatus($transactionId);
}
// Interface implementation
class StripePaymentProcessor implements PaymentProcessorInterface {
private $apiKey;
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function processPayment($amount, $currency) {
// Stripe-specific payment processing
return [
'success' => true,
'transaction_id' => 'stripe_' . uniqid(),
'amount' => $amount,
'currency' => $currency
];
}
public function refundPayment($transactionId) {
// Stripe-specific refund logic
return [
'success' => true,
'refund_id' => 'refund_' . uniqid(),
'transaction_id' => $transactionId
];
}
public function getTransactionStatus($transactionId) {
// Stripe-specific status check
return 'Completed';
}
}
class PayPalPaymentProcessor implements PaymentProcessorInterface {
private $clientId;
private $clientSecret;
public function __construct($clientId, $clientSecret) {
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
}
public function processPayment($amount, $currency) {
// PayPal-specific payment processing
return [
'success' => true,
'transaction_id' => 'paypal_' . uniqid(),
'amount' => $amount,
'currency' => $currency
];
}
public function refundPayment($transactionId) {
// PayPal-specific refund logic
return [
'success' => true,
'refund_id' => 'pp_refund_' . uniqid(),
'transaction_id' => $transactionId
];
}
public function getTransactionStatus($transactionId) {
// PayPal-specific status check
return 'Pending';
}
}
// Using polymorphism
function processOrder($processor, $amount, $currency) {
if (!$processor instanceof PaymentProcessorInterface) {
throw new InvalidArgumentException('Processor must implement PaymentProcessorInterface');
}
$result = $processor->processPayment($amount, $currency);
if ($result['success']) {
echo "Payment processed successfully: {$result['transaction_id']}\n";
return $result['transaction_id'];
} else {
echo "Payment failed\n";
return false;
}
}
$stripeProcessor = new StripePaymentProcessor('sk_test_123');
$paypalProcessor = new PayPalPaymentProcessor('client_123', 'secret_456');
processOrder($stripeProcessor, 100.00, 'USD');
processOrder($paypalProcessor, 75.50, 'EUR');
?>Multiple Interface Implementation
php
<?php
interface Readable {
public function read();
}
interface Writable {
public function write($data);
}
interface Seekable {
public function seek($position);
public function tell();
}
// Class implementing multiple interfaces
class FileHandler implements Readable, Writable, Seekable {
private $file;
private $position = 0;
public function __construct($filename, $mode = 'r+') {
$this->file = fopen($filename, $mode);
if (!$this->file) {
throw new Exception("Cannot open file: $filename");
}
}
public function read() {
return fread($this->file, 1024);
}
public function write($data) {
return fwrite($this->file, $data);
}
public function seek($position) {
$this->position = $position;
return fseek($this->file, $position);
}
public function tell() {
return ftell($this->file);
}
public function __destruct() {
if ($this->file) {
fclose($this->file);
}
}
}
// Interface inheritance
interface DatabaseConnectionInterface {
public function connect();
public function disconnect();
}
interface QueryableInterface extends DatabaseConnectionInterface {
public function query($sql);
public function prepare($sql);
}
interface TransactionalInterface extends QueryableInterface {
public function beginTransaction();
public function commit();
public function rollback();
}
class MySQLConnection implements TransactionalInterface {
private $connection;
private $inTransaction = false;
public function connect() {
// MySQL connection logic
echo "Connected to MySQL\n";
}
public function disconnect() {
// MySQL disconnection logic
echo "Disconnected from MySQL\n";
}
public function query($sql) {
echo "Executing query: $sql\n";
return ['result' => 'data'];
}
public function prepare($sql) {
echo "Preparing statement: $sql\n";
return new stdClass(); // Simulate prepared statement
}
public function beginTransaction() {
$this->inTransaction = true;
echo "Transaction started\n";
}
public function commit() {
if ($this->inTransaction) {
$this->inTransaction = false;
echo "Transaction committed\n";
}
}
public function rollback() {
if ($this->inTransaction) {
$this->inTransaction = false;
echo "Transaction rolled back\n";
}
}
}
?>Interface Constants and Type Hints
php
<?php
interface LoggerInterface {
const LEVEL_DEBUG = 1;
const LEVEL_INFO = 2;
const LEVEL_WARNING = 3;
const LEVEL_ERROR = 4;
const LEVEL_CRITICAL = 5;
public function log($level, $message, array $context = []);
}
class FileLogger implements LoggerInterface {
private $logFile;
public function __construct($logFile) {
$this->logFile = $logFile;
}
public function log($level, $message, array $context = []) {
$levelNames = [
self::LEVEL_DEBUG => 'DEBUG',
self::LEVEL_INFO => 'INFO',
self::LEVEL_WARNING => 'WARNING',
self::LEVEL_ERROR => 'ERROR',
self::LEVEL_CRITICAL => 'CRITICAL'
];
$levelName = $levelNames[$level] ?? 'UNKNOWN';
$timestamp = date('Y-m-d H:i:s');
$contextStr = !empty($context) ? json_encode($context) : '';
$logEntry = "[$timestamp] [$levelName] $message $contextStr\n";
file_put_contents($this->logFile, $logEntry, FILE_APPEND | LOCK_EX);
}
}
// Using interface for type hints
class Application {
private $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
public function run() {
$this->logger->log(LoggerInterface::LEVEL_INFO, 'Application started');
try {
// Application logic
$this->processData();
} catch (Exception $e) {
$this->logger->log(
LoggerInterface::LEVEL_ERROR,
'Application error: ' . $e->getMessage(),
['exception' => get_class($e), 'file' => $e->getFile(), 'line' => $e->getLine()]
);
}
$this->logger->log(LoggerInterface::LEVEL_INFO, 'Application ended');
}
private function processData() {
$this->logger->log(LoggerInterface::LEVEL_DEBUG, 'Processing data');
// Processing logic here
}
}
$logger = new FileLogger('app.log');
$app = new Application($logger);
$app->run();
?>Interacting with Web APIs
Sending HTTP Requests
php
<?php
// Using cURL to send HTTP requests
class HttpClient {
private $baseUrl;
private $defaultHeaders;
public function __construct($baseUrl = '', $defaultHeaders = []) {
$this->baseUrl = rtrim($baseUrl, '/');
$this->defaultHeaders = $defaultHeaders;
}
public function get($endpoint, $headers = []) {
return $this->makeRequest('GET', $endpoint, null, $headers);
}
public function post($endpoint, $data = null, $headers = []) {
return $this->makeRequest('POST', $endpoint, $data, $headers);
}
public function put($endpoint, $data = null, $headers = []) {
return $this->makeRequest('PUT', $endpoint, $data, $headers);
}
public function delete($endpoint, $headers = []) {
return $this->makeRequest('DELETE', $endpoint, null, $headers);
}
private function makeRequest($method, $endpoint, $data = null, $headers = []) {
$url = $this->baseUrl . '/' . ltrim($endpoint, '/');
$allHeaders = array_merge($this->defaultHeaders, $headers);
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $this->formatHeaders($allHeaders),
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false, // Only for development
]);
if ($data !== null) {
if (is_array($data) || is_object($data)) {
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
$allHeaders['Content-Type'] = 'application/json';
} else {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
}
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$error = curl_error($curl);
curl_close($curl);
if ($error) {
throw new Exception("cURL error: $error");
}
return [
'status_code' => $httpCode,
'body' => $response,
'data' => json_decode($response, true)
];
}
private function formatHeaders($headers) {
$formatted = [];
foreach ($headers as $key => $value) {
$formatted[] = "$key: $value";
}
return $formatted;
}
}
// Usage example
$client = new HttpClient('https://jsonplaceholder.typicode.com', [
'User-Agent' => 'PHP HTTP Client 1.0'
]);
try {
// GET request
$response = $client->get('/posts/1');
echo "Status: {$response['status_code']}\n";
echo "Title: {$response['data']['title']}\n";
// POST request
$newPost = [
'title' => 'My New Post',
'body' => 'This is the content of my new post.',
'userId' => 1
];
$response = $client->post('/posts', $newPost);
echo "Created post ID: {$response['data']['id']}\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>API Response Handling
php
<?php
class ApiResponse {
private $statusCode;
private $headers;
private $body;
private $data;
public function __construct($statusCode, $headers, $body) {
$this->statusCode = $statusCode;
$this->headers = $headers;
$this->body = $body;
$this->data = json_decode($body, true);
}
public function isSuccessful() {
return $this->statusCode >= 200 && $this->statusCode < 300;
}
public function isClientError() {
return $this->statusCode >= 400 && $this->statusCode < 500;
}
public function isServerError() {
return $this->statusCode >= 500;
}
public function getStatusCode() {
return $this->statusCode;
}
public function getHeaders() {
return $this->headers;
}
public function getBody() {
return $this->body;
}
public function getData() {
return $this->data;
}
public function getHeader($name) {
return $this->headers[$name] ?? null;
}
}
// API client with response handling
class WeatherApiClient {
private $httpClient;
private $apiKey;
public function __construct($apiKey) {
$this->apiKey = $apiKey;
$this->httpClient = new HttpClient('https://api.openweathermap.org/data/2.5');
}
public function getCurrentWeather($city) {
try {
$response = $this->httpClient->get("/weather", [
'q' => $city,
'appid' => $this->apiKey,
'units' => 'metric'
]);
if ($response['status_code'] === 200) {
return [
'success' => true,
'data' => [
'city' => $response['data']['name'],
'temperature' => $response['data']['main']['temp'],
'description' => $response['data']['weather'][0]['description'],
'humidity' => $response['data']['main']['humidity']
]
];
} else {
return [
'success' => false,
'error' => $response['data']['message'] ?? 'Unknown error'
];
}
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
public function getForecast($city, $days = 5) {
try {
$response = $this->httpClient->get("/forecast", [
'q' => $city,
'appid' => $this->apiKey,
'units' => 'metric',
'cnt' => $days * 8 // 8 forecasts per day (every 3 hours)
]);
if ($response['status_code'] === 200) {
$forecasts = [];
foreach ($response['data']['list'] as $item) {
$forecasts[] = [
'datetime' => $item['dt_txt'],
'temperature' => $item['main']['temp'],
'description' => $item['weather'][0]['description']
];
}
return [
'success' => true,
'data' => [
'city' => $response['data']['city']['name'],
'forecasts' => $forecasts
]
];
} else {
return [
'success' => false,
'error' => $response['data']['message'] ?? 'Unknown error'
];
}
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
}
// Usage
$weatherClient = new WeatherApiClient('your_api_key_here');
$currentWeather = $weatherClient->getCurrentWeather('London');
if ($currentWeather['success']) {
$data = $currentWeather['data'];
echo "{$data['city']} current weather: {$data['temperature']}°C, {$data['description']}\n";
} else {
echo "Error: {$currentWeather['error']}\n";
}
?>Creating RESTful APIs
Basic REST API Structure
php
<?php
// Simple REST API router
class RestApiRouter {
private $routes = [];
public function get($path, $handler) {
$this->addRoute('GET', $path, $handler);
}
public function post($path, $handler) {
$this->addRoute('POST', $path, $handler);
}
public function put($path, $handler) {
$this->addRoute('PUT', $path, $handler);
}
public function delete($path, $handler) {
$this->addRoute('DELETE', $path, $handler);
}
private function addRoute($method, $path, $handler) {
$this->routes[] = [
'method' => $method,
'path' => $path,
'handler' => $handler
];
}
public function handle() {
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
foreach ($this->routes as $route) {
if ($route['method'] === $method && $this->matchPath($route['path'], $path)) {
$params = $this->extractParams($route['path'], $path);
return call_user_func($route['handler'], $params);
}
}
$this->sendResponse(404, ['error' => 'Route not found']);
}
private function matchPath($routePath, $requestPath) {
$routePattern = preg_replace('/\{[^}]+\}/', '([^/]+)', $routePath);
return preg_match("#^{$routePattern}$#", $requestPath);
}
private function extractParams($routePath, $requestPath) {
$params = [];
$routeParts = explode('/', $routePath);
$requestParts = explode('/', $requestPath);
for ($i = 0; $i < count($routeParts); $i++) {
if (preg_match('/\{([^}]+)\}/', $routeParts[$i], $matches)) {
$paramName = $matches[1];
$params[$paramName] = $requestParts[$i] ?? null;
}
}
return $params;
}
private function sendResponse($statusCode, $data) {
http_response_code($statusCode);
header('Content-Type: application/json');
echo json_encode($data);
exit;
}
}
// User API controller
class UserApiController {
private $users = [
1 => ['id' => 1, 'name' => 'Zhang San', 'email' => 'zhangsan@example.com'],
2 => ['id' => 2, 'name' => 'Li Si', 'email' => 'lisi@example.com'],
3 => ['id' => 3, 'name' => 'Wang Wu', 'email' => 'wangwu@example.com']
];
public function getAllUsers($params) {
$this->sendResponse(200, array_values($this->users));
}
public function getUser($params) {
$id = (int)$params['id'];
if (isset($this->users[$id])) {
$this->sendResponse(200, $this->users[$id]);
} else {
$this->sendResponse(404, ['error' => 'User not found']);
}
}
public function createUser($params) {
$input = json_decode(file_get_contents('php://input'), true);
if (!$input || !isset($input['name']) || !isset($input['email'])) {
$this->sendResponse(400, ['error' => 'Name and email are required']);
}
$id = max(array_keys($this->users)) + 1;
$user = [
'id' => $id,
'name' => $input['name'],
'email' => $input['email']
];
$this->users[$id] = $user;
$this->sendResponse(201, $user);
}
public function updateUser($params) {
$id = (int)$params['id'];
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($this->users[$id])) {
$this->sendResponse(404, ['error' => 'User not found']);
}
if ($input) {
if (isset($input['name'])) {
$this->users[$id]['name'] = $input['name'];
}
if (isset($input['email'])) {
$this->users[$id]['email'] = $input['email'];
}
}
$this->sendResponse(200, $this->users[$id]);
}
public function deleteUser($params) {
$id = (int)$params['id'];
if (isset($this->users[$id])) {
unset($this->users[$id]);
$this->sendResponse(204, null);
} else {
$this->sendResponse(404, ['error' => 'User not found']);
}
}
private function sendResponse($statusCode, $data) {
http_response_code($statusCode);
header('Content-Type: application/json');
if ($data !== null) {
echo json_encode($data);
}
exit;
}
}
// API setup
$router = new RestApiRouter();
$userController = new UserApiController();
// Define routes
$router->get('/api/users', [$userController, 'getAllUsers']);
$router->get('/api/users/{id}', [$userController, 'getUser']);
$router->post('/api/users', [$userController, 'createUser']);
$router->put('/api/users/{id}', [$userController, 'updateUser']);
$router->delete('/api/users/{id}', [$userController, 'deleteUser']);
// Handle request
$router->handle();
?>API Authentication and Middleware
php
<?php
// JWT token handler (simplified)
class JwtHandler {
private $secret;
public function __construct($secret) {
$this->secret = $secret;
}
public function generateToken($payload) {
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
$payload = json_encode($payload);
$base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
$base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
$signature = hash_hmac('sha256', $base64Header . "." . $base64Payload, $this->secret, true);
$base64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
return $base64Header . "." . $base64Payload . "." . $base64Signature;
}
public function validateToken($token) {
$parts = explode('.', $token);
if (count($parts) !== 3) {
return false;
}
[$header, $payload, $signature] = $parts;
$validSignature = hash_hmac('sha256', $header . "." . $payload, $this->secret, true);
$validBase64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($validSignature));
if ($signature !== $validBase64Signature) {
return false;
}
$decodedPayload = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $payload)), true);
// Check expiration
if (isset($decodedPayload['exp']) && $decodedPayload['exp'] < time()) {
return false;
}
return $decodedPayload;
}
}
// Authentication middleware
class AuthMiddleware {
private $jwtHandler;
public function __construct(JwtHandler $jwtHandler) {
$this->jwtHandler = $jwtHandler;
}
public function authenticate() {
$headers = getallheaders();
$authHeader = $headers['Authorization'] ?? '';
if (!preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
$this->sendUnauthorized('Missing or invalid authorization header');
}
$token = $matches[1];
$payload = $this->jwtHandler->validateToken($token);
if (!$payload) {
$this->sendUnauthorized('Invalid or expired token');
}
return $payload;
}
private function sendUnauthorized($message) {
http_response_code(401);
header('Content-Type: application/json');
echo json_encode(['error' => $message]);
exit;
}
}
// Protected API controller
class ProtectedApiController {
private $authMiddleware;
public function __construct(AuthMiddleware $authMiddleware) {
$this->authMiddleware = $authMiddleware;
}
public function getProfile($params) {
$user = $this->authMiddleware->authenticate();
// Return user profile
$this->sendResponse(200, [
'id' => $user['user_id'],
'name' => $user['name'],
'email' => $user['email']
]);
}
public function updateProfile($params) {
$user = $this->authMiddleware->authenticate();
$input = json_decode(file_get_contents('php://input'), true);
// Update user profile logic here
$this->sendResponse(200, ['message' => 'Profile updated successfully']);
}
private function sendResponse($statusCode, $data) {
http_response_code($statusCode);
header('Content-Type: application/json');
echo json_encode($data);
exit;
}
}
// Login controller
class AuthController {
private $jwtHandler;
private $users = [
'zhangsan@example.com' => ['id' => 1, 'name' => 'Zhang San', 'password' => 'password123'],
'lisi@example.com' => ['id' => 2, 'name' => 'Li Si', 'password' => 'secret456']
];
public function __construct(JwtHandler $jwtHandler) {
$this->jwtHandler = $jwtHandler;
}
public function login($params) {
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['email']) || !isset($input['password'])) {
$this->sendResponse(400, ['error' => 'Email and password are required']);
}
$email = $input['email'];
$password = $input['password'];
if (!isset($this->users[$email]) || $this->users[$email]['password'] !== $password) {
$this->sendResponse(401, ['error' => 'Invalid credentials']);
}
$user = $this->users[$email];
$payload = [
'user_id' => $user['id'],
'name' => $user['name'],
'email' => $email,
'exp' => time() + 3600 // 1 hour expiration
];
$token = $this->jwtHandler->generateToken($payload);
$this->sendResponse(200, [
'token' => $token,
'user' => [
'id' => $user['id'],
'name' => $user['name'],
'email' => $email
]
]);
}
private function sendResponse($statusCode, $data) {
http_response_code($statusCode);
header('Content-Type: application/json');
echo json_encode($data);
exit;
}
}
// Setup
$jwtHandler = new JwtHandler('your-secret-key');
$authMiddleware = new AuthMiddleware($jwtHandler);
$authController = new AuthController($jwtHandler);
$protectedController = new ProtectedApiController($authMiddleware);
// Routes
$router = new RestApiRouter();
$router->post('/api/login', [$authController, 'login']);
$router->get('/api/profile', [$protectedController, 'getProfile']);
$router->put('/api/profile', [$protectedController, 'updateProfile']);
$router->handle();
?>API Documentation and Testing
API Documentation Generator
php
<?php
/**
* @api {get} /api/users Get all users
* @apiName GetUsers
* @apiGroup User
*
* @apiSuccess {Object[]} users User list
* @apiSuccess {Number} users.id User ID
* @apiSuccess {String} users.name User name
* @apiSuccess {String} users.email User email
*
* @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK
* [
* {
* "id": 1,
* "name": "Zhang San",
* "email": "zhangsan@example.com"
* }
* ]
*/
class ApiDocumentationGenerator {
private $routes = [];
public function addRoute($method, $path, $description, $parameters = [], $responses = []) {
$this->routes[] = [
'method' => strtoupper($method),
'path' => $path,
'description' => $description,
'parameters' => $parameters,
'responses' => $responses
];
}
public function generateHtml() {
$html = '<!DOCTYPE html>
<html>
<head>
<title>API Documentation</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.route { margin-bottom: 30px; border: 1px solid #ddd; padding: 20px; }
.method { display: inline-block; padding: 5px 10px; color: white; font-weight: bold; }
.get { background-color: #61affe; }
.post { background-color: #49cc90; }
.put { background-color: #fca130; }
.delete { background-color: #f93e3e; }
.path { font-family: monospace; font-size: 18px; margin-left: 10px; }
.parameters, .responses { margin-top: 15px; }
table { width: 100%; border-collapse: collapse; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>API Documentation</h1>';
foreach ($this->routes as $route) {
$methodClass = strtolower($route['method']);
$html .= "<div class='route'>";
$html .= "<span class='method {$methodClass}'>{$route['method']}</span>";
$html .= "<span class='path'>{$route['path']}</span>";
$html .= "<p>{$route['description']}</p>";
if (!empty($route['parameters'])) {
$html .= "<div class='parameters'><h4>Parameters:</h4>";
$html .= "<table><tr><th>Name</th><th>Type</th><th>Required</th><th>Description</th></tr>";
foreach ($route['parameters'] as $param) {
$required = $param['required'] ? 'Yes' : 'No';
$html .= "<tr><td>{$param['name']}</td><td>{$param['type']}</td><td>{$required}</td><td>{$param['description']}</td></tr>";
}
$html .= "</table></div>";
}
if (!empty($route['responses'])) {
$html .= "<div class='responses'><h4>Responses:</h4>";
foreach ($route['responses'] as $response) {
$html .= "<h5>HTTP {$response['code']}</h5>";
$html .= "<pre>" . htmlspecialchars($response['example']) . "</pre>";
}
$html .= "</div>";
}
$html .= "</div>";
}
$html .= '</body></html>';
return $html;
}
}
// Usage
$docs = new ApiDocumentationGenerator();
$docs->addRoute('GET', '/api/users', 'Get all users', [], [
['code' => 200, 'example' => json_encode([
['id' => 1, 'name' => 'Zhang San', 'email' => 'zhangsan@example.com']
], JSON_PRETTY_PRINT)]
]);
$docs->addRoute('POST', '/api/users', 'Create new user', [
['name' => 'name', 'type' => 'string', 'required' => true, 'description' => 'User name'],
['name' => 'email', 'type' => 'string', 'required' => true, 'description' => 'User email']
], [
['code' => 201, 'example' => json_encode([
'id' => 4, 'name' => 'New User', 'email' => 'new@example.com'
], JSON_PRETTY_PRINT)]
]);
echo $docs->generateHtml();
?>Next Steps
Now that you understand APIs and interfaces, let's explore error handling in Error Handling.
Practice Exercises
- Create a complete RESTful API for a blog system
- Build API clients for popular web services (GitHub, Twitter, etc.)
- Implement API rate limiting and caching
- Create an API gateway that routes requests to different services
- Build a webhook system for real-time notifications
Understanding APIs and interfaces is essential for building modern, interconnected PHP applications!