Guide
Getting started
This page assumes the php kernel is installed and juphyter doctor reports it as ready. Installation covers both. The examples were run in a Quarto document, and they behave the same way in a JupyterLab notebook.
To follow along in JupyterLab, run jupyter lab from an environment that has it, such as ~/.venvs/juphyter/bin/jupyter lab, and choose the PHP kernel in the launcher. To follow along in Quarto, create a file first.qmd:
---
title: "A first PHP document"
jupyter: php
---
```{php}
echo "sum: ", array_sum(range(1, 10)), "\n";
```Then run quarto render first.qmd, which writes first.html.
A first cell
A cell holds PHP without an opening <?php tag. Whatever the cell prints with echo appears first, and the value of its last expression appears after it.
$primes = [2, 3, 5, 7, 11, 13];
echo count($primes), " primes, summing to ", array_sum($primes), "\n";
array_sum($primes) / count($primes);6 primes, summing to 41
6.833333333333333
A cell whose last expression is a statement or a call that returns null shows only what it printed.
State between cells
Variables, objects, functions, and classes carry from one cell to the next.
$primes[] = 17;
$primes;[2, 3, 5, 7, 11, 13, 17]
Restarting the kernel starts a new PHP session with nothing defined. In JupyterLab, use Kernel > Restart Kernel. Each quarto render starts a new session.
Imports
A use statement applies to its own cell and to every later cell. A notebook can put its imports in its first cell and use short names afterward. This example uses phibble, which the php kernel finds when the document sits inside a Composer project that requires it, or which the phpstats kernel from Installation provides.
use Phibble\DataFrame;$orders = DataFrame::fromRows([
['channel' => 'web', 'region' => 'north', 'total' => 120.50],
['channel' => 'store', 'region' => 'north', 'total' => 80.00],
['channel' => 'web', 'region' => 'south', 'total' => 42.25],
]);
$orders;| channel <chr> | region <chr> | total <dbl> | |
|---|---|---|---|
| 1 | web | north | 120.5 |
| 2 | store | north | 80 |
| 3 | web | south | 42.25 |
A cell cannot declare a namespace, and it cannot declare a class or a function that an earlier cell already declared. Limitations explains both.
Errors
A cell that throws shows the exception, its message, and a traceback whose lines name the cell and the line number.
$mean = fn (array $values) => array_sum($values) / count($values);
$mean([]);DivisionByZeroError: Division by zero
DivisionByZeroError: Division by zero
in a closure
at Cell 5, line 3
The session survives the exception. Variables defined before it keep their values.
Warnings, notices, and deprecations appear in the cell’s error output, and the cell keeps running.
$widths = ['narrow' => 4, 'wide' => 12];
$widths['narrow'] + $widths['medium'];Warning: Undefined array key "medium" in Cell 6, line 3
4
Rich output
The kernel sends each value in every format it can produce, and the front end picks the one it can draw. A phibble data frame comes as an HTML table and as the text phibble prints at a terminal. A phiz plot comes as a Vega-Lite specification, as HTML, as a static SVG when vl-convert is installed, and as a one-line text description.
Any class can provide its own output. A toHtml(): string method supplies HTML, and a toMimeBundle(): array method supplies every format at once.
final class Progress
{
public function __construct(private readonly int $done, private readonly int $total) {}
public function toHtml(): string
{
return sprintf(
'<progress value="%d" max="%d"></progress> %d of %d',
$this->done,
$this->total,
$this->done,
$this->total,
);
}
public function __toString(): string
{
return sprintf('%d of %d', $this->done, $this->total);
}
}
new Progress(7, 9);Juphyter\display() shows a value part way through a cell, so one cell can show several tables or plots.
Juphyter\display(new Progress(3, 9));
Juphyter\display(new Progress(9, 9));