Playground API Client
The PlaygroundClient object implements the UniversalPHP interface. All the methods from that interface are also available in Node.js and same-process PHP instances (Playground runs PHP in a web worker).
Broadly speaking, you can use the client to perform three types of operations:
- Running PHP code
- Customizing
PHP.ini - Managing files and directories
SharedWorker runtime
startPlaygroundWeb() uses a dedicated worker by default. Applications can opt into
sharing one PHP runtime across tabs on the same origin and browser storage partition.
Serve the matching client and remote runtime from the application's own deployment:
const client = await startPlaygroundWeb({
iframe: document.getElementById('wp'),
remoteUrl: new URL('/remote.html', window.location.href).href,
workerMode: 'shared',
scope: 'my-site',
});
Shared mode requires browser SharedWorker support and an explicit scope. Tabs using
the same scope and build share the initialized site; use different scopes for independent
runtimes. Only the initializing connection runs its startup Blueprint. Closing its tab
once initialization finishes does not interrupt the other tabs. The main Playground
website continues to use dedicated workers.
By default, both version options use the remote runtime's build version. Applications
that check deployments themselves can pass sharedWorkerVersion for the current deployment
and sharedWorkerClientVersion for the build loaded by the connecting application. If they
differ, the tab must reload before connecting. A new deployment discovers the previous
worker through localStorage and waits for its shutdown confirmation before replacement.
If that identity is lost or the worker cannot be reached, a replacement may start while
the previous runtime is still running; there is no ownership lock.
The embedding application must handle same-origin playground-reload-required messages
from its remote iframe and offer a tab reload. The message's ready field indicates
whether shutdown is complete; otherwise wait for playground-runtime-closed before
allowing reload. A shared-runtime-retirement-error message reports a retirement failure.
Validate the message origin and source against the embedded remote iframe.
await client.shutdownSharedRuntime() explicitly retires the runtime for all connected
tabs: it rejects new work, drains active operations, flushes OPFS, and disposes PHP. It
rejects if retirement fails and is a no-op in dedicated mode. The
shouldRunStartupBlueprint() and finishSharedRuntimeInitialization() methods are
internal startup coordination hooks; applications should let startPlaygroundWeb() call them.
Running PHP code
The two methods you can use to run PHP code are:
In Node.js, you can also use the cli() method to run PHP in a CLI mode.
The run() method
The request() method
Serves the request – either by serving a static file, or by dispatching it to the PHP runtime.
The request() method mode behaves like a web server and only works if
the PHP was initialized with a requestHandler option (which the online
version of WordPress Playground does by default).
In the request mode, you pass an object containing the request information (method, headers, body, etc.) and the URL to request:
await client.writeFile(
'/index.php',
`<?php echo file_get_contents('php://input');`
);
const result = await client.request({
url: '/index.php',
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
body: 'Hello world!',
});
// result.text === 'Hello world!'
The request() method cannot be used in conjunction with cli().
Customizing PHP.ini
The API client also allows you to change the php.ini file:
await setPhpIniEntries(client, {
display_errors: 'On',
error_reporting: 'E_ALL',
});
Managing files and directories
The client object provides you with a low-level API for managing files and directories in the PHP filesystem:
await client.mkdirTree('/wordpress/test');
// Create a new PHP file
await client.writeFile(
'/wordpress/test/index.php',
`<?php
echo "Hello, world!<br/>";
// List all the files in current directory
print_r(glob(__DIR__ . '/*'));
`
);
// Create files named 1, 2, and 3
await client.writeFile('/wordpress/test/1', '');
await client.writeFile('/wordpress/test/2', '');
await client.writeFile('/wordpress/test/3', '');
// Remove the file named 1
await client.unlink('/wordpress/test/1');
// Navigate to our PHP file
await client.goTo('/test/index.php');
For a complete list of these methods, refer to the PlaygroundClient interface.
Sending messages to JavaScript
You can pass messages from PHP to JavaScript using the post_message_to_js() function. It accepts one argument:
$data(string) – Data to pass to JavaScript.
For example, here's how you would send a message with a JSON-encoded post ID and title:
import { PHP } from '@php-wasm/universal';
import { loadNodeRuntime } from '@php-wasm/node';
const php = new PHP(await loadNodeRuntime('8.3'));
php.onMessage(
// The data is always passed as a string
function (data: string) {
// Let's decode and log the data:
console.log(JSON.parse(data));
}
);
// Now that we have a listener in place, let's
// dispatch a message:
await php.runStream({
code: `<?php
post_message_to_js(
json_encode([
'post_id' => '15',
'post_title' => 'This is a blog post!'
])
);
`,
});
// You will see the following output in the console:
// { post_id: '15', post_title: 'This is a blog post!' }
The cli() method
In Node.js, you also have access to the cli() method that runs PHP in a CLI mode:
// Run PHP in a CLI mode
client.cli(['-r', 'echo "Hello, world!";']);
// Outputs "Hello, world!"
Once cli() method finishes running, the PHP instance is no longer usable and should be discarded. This is because PHP internally cleans up all the resources and calls exit().