Guide
Installation
Requirements
- PHP 8.3, 8.4, or 8.5. CI tests all three.
- The
mbstringandtokenizerPHP extensions. Most PHP builds include both. juphyter 0.1.1 and later declare both in composer.json, so Composer reports a missing one at install time. - Composer.
- Python 3 with the
venvmodule. On Debian and Ubuntu that module is thepython3-venvpackage. - macOS or Linux.
Optional:
- The
pcntlPHP extension makes the stop button interrupt a running cell. Without it the kernel runs and the stop button does nothing. - Quarto renders
.qmddocuments. CI tests Quarto 1.10.18. - The vl-convert binary gives phiz plots a static image for PDF and Word output. Quarto covers when it is needed.
juphyter does not use the posix or sockets PHP extensions.
The kernel runs inside a Python environment that has ipykernel 7.0 or later. juphyter install uses an existing environment that has it, or builds one with JupyterLab in it. ipykernel 7.4, the current release, requires Python 3.11 or later. The commands below were run on 2026-10-31 with juphyter 0.1.0, on macOS with Python 3.14 and on Debian 13 with Python 3.13.
Install
Install juphyter once for your user. A kernel is registered for the user, so one install serves notebooks and documents in every directory.
composer global require phpstats/juphyter
export PATH="$(composer global config bin-dir --absolute):$PATH"
juphyter install --create-venv ~/.venvs/juphyter
export PATH="$HOME/.venvs/juphyter/bin:$PATH"
juphyter doctorThe commands do the following:
composer global requireinstalls juphyter into Composer’s global directory.- The first
exportputs Composer’s bin directory onPATHfor this shell, so thejuphytercommand is found. juphyter installregisters the kernel with Jupyter under the namephp. It uses the Python environment that owns thejupytercommand onPATHwhen that environment has ipykernel. Otherwise it builds a virtual environment with JupyterLab at the path--create-venvnames, using the Python already on the machine. It changes no existing Python installation.- The second
exportputs that environment first onPATHfor this shell, sojupyter labandquarto renderfind it. When step 3 used an existing environment, the directory does not exist and the line has no effect. juphyter doctorchecks the installation. It changes nothing.
Both export lines last until the shell closes.
juphyter install prints what it registered:
Installed the juphyter kernel "php" for PHP 8.5.10.
kernel.json /Users/you/Library/Jupyter/kernels/php/kernel.json
python /Users/you/.venvs/juphyter/bin/python (ipykernel 7.4.0)
php /opt/homebrew/Cellar/php/8.5.10/bin/php
engine /Users/you/.composer/vendor/phpstats/juphyter/bin/juphyter
quarto /opt/homebrew/opt/[email protected]/bin/python3.14 (no Jupyter)
The quarto line names the Python that Quarto would use from this shell. It appears only when Quarto is installed. Here it was printed before the second export, so it names a Python without Jupyter, and the command also printed a warning with the export line that fixes it. The kernel is still registered, and the command exits 0.
On Homebrew, juphyter 0.1.0 recorded the versioned path under Cellar shown above, which brew upgrade removes. juphyter 0.1.1 and later record the first path on PATH with the same name that leads to the running PHP, such as /opt/homebrew/bin/php. With 0.1.0, pass that path explicitly:
juphyter install --php /opt/homebrew/bin/phpKeeping the PATH entries
To keep the juphyter command available in new shells, add Composer’s bin directory to your shell startup file. This edits ~/.zshrc, the zsh startup file. Use ~/.bashrc for bash.
echo "export PATH=\"$(composer global config bin-dir --absolute):\$PATH\"" >> ~/.zshrcAdding the Python environment to a startup file makes it the python3 for every program in every shell, including every Quarto project on the machine. Python interpreters and editors describes how to select it per editor workspace, per shell, or per Quarto project instead.
Check the installation
juphyter doctorjuphyter doctor checks juphyter’s own files, the PHP that runs the cells, the Python for the kernel, the Python Quarto will use, and every kernel juphyter registered. It ends with one line for JupyterLab and one for Quarto. After the install above:
juphyter doctor
This package
ok the Python wrapper is at /Users/you/.composer/vendor/phpstats/juphyter/kernel/juphyter_kernel
PHP
ok PHP 8.5.10 at /opt/homebrew/Cellar/php/8.5.10/bin/php
ok pcntl is there, so the stop button interrupts a cell
A Python for the kernel
ok /Users/you/.venvs/juphyter/bin/python has ipykernel 7.4.0
Quarto
ok quarto will run /Users/you/.venvs/juphyter/bin/python3, with jupyter_client 8.10.0
Kernels in /Users/you/Library/Jupyter/kernels
ok php is complete
JupyterLab: ready, with php.
Quarto: ready.
A line marked fail makes the command exit 1. A line marked warn does not. A missing pcntl is a warning.
In a shell where the Python environment is not on PATH, the Quarto section fails, the summary reads Quarto: not ready., and the report ends with the export line that fixes it. JupyterLab still works if you start it from the environment, for example ~/.venvs/juphyter/bin/jupyter lab.
Run juphyter doctor again after upgrading PHP or Python, or after removing a project or an environment. The kernel records absolute paths to a PHP binary, a Python interpreter, and juphyter itself, and the doctor reports any of them that no longer runs.
The phpstats packages
juphyter does not depend on phibble, phplyr, or phiz. To use them in notebooks outside any Composer project, install them globally and register a second kernel that loads Composer’s global autoloader:
composer global require phpstats/phibble phpstats/phplyr phpstats/phiz
juphyter install --name phpstats --display-name "PHP (phpstats)" \
--autoload "$(composer global config home)/vendor/autoload.php"Documents name that kernel as jupyter: phpstats, and JupyterLab lists it as “PHP (phpstats)”.
The php kernel keeps the default search for an autoloader, described below. A kernel installed with --autoload always loads the autoloader it names, even for a notebook inside a Composer project, which is why it has its own name.
Which classes a notebook sees
By default the kernel starts in the notebook’s directory, looks upward for vendor/autoload.php, and loads the first one it finds. A notebook anywhere inside a Composer project can use that project’s classes and packages with no configuration.
Two settings replace that search. The more explicit one wins.
JUPHYTER_AUTOLOADin the kernel’s environment.juphyter install --autoload PATHrecords it in the kernel.- A
juphyter.jsonin the notebook’s directory or any directory above it.
A juphyter.json can also set the memory limit and the include path:
{
"autoload": "vendor/autoload.php",
"memory_limit": "512M",
"include_path": "lib"
}Relative paths resolve against the directory that holds juphyter.json, so one file at a project’s root serves every notebook below it.
Installing into one project
juphyter can also be a development dependency of a project:
composer require --dev phpstats/juphyter
vendor/bin/juphyter install --name myprojectThe kernel is still registered for your user, and it runs that project’s copy of juphyter. Without --name, a second project’s install replaces the first project’s php kernel, and the command reports it as Replaced. Deleting the project’s vendor directory breaks the kernel, which juphyter doctor reports.
Several PHP versions
Give each kernel its own name:
juphyter install --name php83 --php /opt/homebrew/opt/[email protected]/bin/php
juphyter install --name php85 --php /opt/homebrew/opt/[email protected]/bin/phpJupyterLab then lists “PHP 8.3” and “PHP 8.5”. --display-name sets the label yourself. An absolute --php path is recorded as written. A bare name such as php8.4 is resolved to an absolute path, because a kernel cannot rely on PATH.
Where the kernel is registered
juphyter install writes a kernelspec, the kernel.json file Jupyter reads to start a kernel, into the per-user Jupyter data directory:
~/Library/Jupyter/kernelson macOS.$XDG_DATA_HOME/jupyter/kernels, or~/.local/share/jupyter/kernels, on Linux.
It honors JUPYTER_DATA_DIR and JUPYTER_PLATFORM_DIRS as jupyter --paths reports them. --prefix PATH writes under PATH/share/jupyter instead. Every Jupyter installation on the machine searches the per-user directory, so the kernel is visible to all of them.
juphyter uninstall --name NAME removes a kernel that juphyter registered. It refuses to remove a kernel of the same name that something else wrote, and so does a reinstall.
Options
juphyter install --help lists every option:
| Option | Meaning |
|---|---|
--name NAME |
The kernel’s name, which documents use in jupyter: NAME. Default: php. |
--display-name TEXT |
The label JupyterLab shows. Default: the PHP version, such as PHP 8.5. |
--php PATH |
The PHP binary that runs cells. Default: the PHP running juphyter install. |
--python PATH |
The Python that hosts the kernel. Default: the one that owns jupyter on PATH. A named Python without ipykernel is reported, and nothing is installed into it. |
--prefix PATH |
Write under PATH/share/jupyter. |
--autoload PATH |
Load this autoloader instead of searching above the notebook. |
--create-venv PATH |
Where to build a Python environment when none can host the kernel. Without it, the command asks, and builds one at ~/.venvs/juphyter when there is no terminal to ask. |
juphyter --version prints the installed version and the PHP running it.