Boson PHP è una piattaforma per creare applicazioni desktop multipiattaforma usando tecnologie web familiari come PHP, JavaScript, HTML e CSS. La filosofia alla base è consentire agli sviluppatori PHP di creare applicazioni native per Windows, Linux e macOS in modo semplice e performante, con un unico file eseguibile. I vantaggi principali del progetto includono:
- Leggerezza e performance elevate.
- Semplicità d’uso per gli sviluppatori PHP.
- Supporto nativo per componenti web attraverso un motore WebView integrato.
Il progetto è guidato dal maintainer Kirill Nesmejanov, con contributi da Alexey Gagarin, Dmitrij Derepko e Danil Shcutskij.
I Web Components
I web components sono una caratteristica principale di Boson. In questo progetto funzionano registrando componenti personalizzati PHP che possono essere istanziati e usati come tag HTML.
Creare il primo componente
class MioPulsanteFantastico {}
$applicazione = new Boson\Application();
// Nome del tag
$nomeTag = 'mio-pulsante';
// Classe del componente
$classeComponente = MioPulsanteFantastico::class;
// Registrazione
$applicazione->webview->components->add($nomeTag, $classeComponente);
// Impostiamo il contenuto HTML
$applicazione->webview->html = '<mio-pulsante>Premimi!</mio-pulsante>';
Regola importante: il nome del tag personalizzato deve contenere un trattino.
Creare template personalizzati
È possibile personalizzare l’aspetto dei componenti.
Esempio di template HTML standard
class MioPulsanteConStile implements HasTemplateInterface
{
public function render(): string
{
return <<<HTML
<button class="btn-stiloso">Cliccami!</button>
HTML;
}
}
Shadow DOM per stili isolati
class MiaCarta implements HasShadowDomInterface
{
public function render(): string
{
return <<<HTML
<div class="scheda">
<h3>Titolo della scheda</h3>
<slot></slot>
</div>
HTML;
}
}
Con Shadow DOM gli stili e il contenuto del tuo componente restano isolati dal resto della pagina.
Gestione del ciclo di vita
Vuoi sapere quando un componente appare o scompare dalla pagina?
class MioComponenteConCiclo implements HasLifecycleCallbacksInterface
{
public function onConnect(): void
{
echo "Componente connesso!";
}
public function onDisconnect(): void
{
echo "Componente rimosso!";
}
}
Interattività: Proprietà, Metodi, Attributi ed Eventi
Proprietà sincronizzate con JavaScript
class Contatore implements HasPropertiesInterface
{
public function onPropertyChanged(string $nomeProprieta, mixed $valore): void
{
if ($nomeProprieta === 'conta') {
echo "Valore contatore aggiornato: $valore";
}
}
public static function getPropertyNames(): array
{
return ['conta'];
}
}
// In JavaScript
let contatore = document.createElement('mio-contatore');
contatore.conta = 10;
Metodi richiamabili da JavaScript
class Calcolatrice implements HasMethodsInterface
{
public function onMethodCalled(string $metodo, array $argomenti = []): mixed
{
switch ($metodo) {
case 'somma':
return $argomenti[0] + $argomenti[1];
case 'saluta':
return "Ciao dal PHP!";
default:
throw new \BadMethodCallException("Metodo non trovato: $metodo");
}
}
public static function getMethodNames(): array
{
return ['somma', 'saluta'];
}
}
// In HTML/JS
<my-calculator onclick="this.saluta()">Calcolatrice</my-calculator>
Rilevamento attributi modificati
class BadgeStato implements HasAttributesInterface
{
public function onAttributeChanged(string $nomeAttributo, ?string $valore, ?string $precedente): void
{
echo "Attributo $nomeAttributo cambiato da $precedente a $valore";
}
public static function getAttributeNames(): array
{
return ['stato'];
}
}
Gestione eventi dal browser
class GestoreEventi implements HasEventListenersInterface
{
public function onEventFired(string $evento, array $argomenti = []): void
{
if ($evento === 'click') {
echo "Click rilevato!";
}
}
public static function getEventListeners(): array
{
return ['click' => []];
}
}
Contesto reattivo
Il “contesto reattivo” è un potente strumento per controllare programmaticamente lo stato del componente. In pratica PHP può modificare il contenuto HTML del componente, aggiungere o rimuovere attributi e aggiornare proprietà osservate da JS, in maniera del tutto dinamica.
ReactiveContext non è un semplice helper, ma il canale di comunicazione diretto tra PHP (logica applicativa) e DOM della WebView (HTML + JS). È un oggetto che rappresenta lo stato vivo del componente nel browser. Contiene principalmente tre aree:
attributes→ attributi HTML del componentecontent→ contenuto HTML interno- (in altri contesti anche
properties,events, ecc.)
Quando modifichi il ReactiveContext, non stai preparando HTML ma stai modificando direttamente il DOM già renderizzato. In pratica: ogni <componente-reattivo> nel DOM ha il suo ReactiveContextisolato dagli altri
use Boson\WebView\Api\WebComponents\ReactiveContext;
class ComponenteReattivo implements HasMethodsInterface
{
public function __construct(private ReactiveContext $ctx) {}
public function refresh(): void
{
if (!$this->ctx->attributes->has('caricato')) {
$this->ctx->attributes->set('caricato', 'true');
}
if ($this->ctx->content->html === '') {
$this->ctx->content->html = '<p>Contenuto caricato!</p>';
}
}
public function onMethodCalled(string $metodo, array $argomenti = []): mixed
{
if ($metodo === 'refresh') {
$this->refresh();
return 'Aggiornato!';
}
return '';
}
public static function getMethodNames(): array //dichiara esplicitamente quali metodi sono esposti a JS
{
return ['refresh'];
}
}
L’effetto reale nel DOM sarà quello di aggiungere un attributo caricato = true.
<componente-reattivo caricato="true"></componente-reattivo>
E’ importante sapere che questo effetto condiziona l’HTML esistente. Quindi non viene generata una stringa HTML, ma ribadisco, è una modifica diretta dell’elemento DOM in cui JS può reagire immediatamente a questo cambiamento.
Per quanto riguarda la funzionefunction onMethodCalled(string $metodo, array $argomenti = []): mixed viene chiamato automaticamente da Boson quando JavaScript invoca un metodo sul componente. In javascript poi potrò gestire il componente richiamandolo così:
document
.querySelector('componente-reattivo')
.refresh();
Cosa succede dietro le quinte?
- JS chiama
refresh() - Boson intercetta la chiamata
- PHP riceve
"refresh"come$metodo - PHP esegue
refresh() - PHP aggiorna DOM e attributi
- PHP restituisce un valore a JS
Architettura consigliata di un’applicazione Boson PHP
Una delle domande più frequenti è: come strutturare correttamente un progetto Boson PHP?
Una buona pratica è separare chiaramente:
- Logica applicativa PHP
- Componenti Web
- Risorse statiche (CSS, JS)
- Bootstrap dell’applicazione
Esempio di struttura delle cartelle
/app
/Componenti
PulsantePrimario.php
BarraNavigazione.php
FinestraDialogo.php
/Servizi
GestoreUtenti.php
ArchivioDati.php
/public
style.css
script.js
/main.php
Questo approccio rende il progetto scalabile e facilmente manutenibile.
Bootstrap dell’applicazione
Il file main.php rappresenta il punto di ingresso dell’applicazione.
use Boson\Application; $app = new Application(); $app->webview->html = file_get_contents(__DIR__ . '/public/index.html'); $app->run();
In questo modo puoi mantenere l’HTML separato dal codice PHP, come in una classica applicazione web.
Registrazione automatica dei Web Components
Quando il numero di componenti cresce, registrarli manualmente diventa scomodo. È possibile automatizzare il processo in questo modo:
$componenti = [
'pulsante-primario' => App\Componenti\PulsantePrimario::class,
'barra-navigazione' => App\Componenti\BarraNavigazione::class,
];
foreach ($componenti as $tag => $classe) {
$app->webview->components->add($tag, $classe);
}
Questo pattern è simile a quello utilizzato nei service provider dei framework PHP moderni.
Integrazione con database e servizi
Un componente Boson non deve contenere direttamente la logica di business. È preferibile delegarla a servizi dedicati.
Esempio: servizio utenti
class GestoreUtenti
{
public function ottieniNomeUtente(int $id): string
{
return "Utente #" . $id;
}
}
Uso del servizio in un componente
class ProfiloUtente implements HasTemplateInterface
{
public function __construct(
private GestoreUtenti $utenti
) {}
public function render(): string
{
$nome = $this->utenti->ottieniNomeUtente(1);
return "<div>Profilo di $nome</div>";
}
}
Questo approccio favorisce testabilità e separazione delle responsabilità.
Comunicazione avanzata JavaScript / PHP
Uno degli aspetti più innovativi di Boson PHP è la comunicazione bidirezionale nativa tra PHP e JavaScript. A differenza delle applicazioni web tradizionali, dove frontend e backend comunicano tramite HTTP, fetch, AJAX o WebSocket, Boson elimina completamente il livello di rete.
In Boson:
- PHP e JavaScript convivono nello stesso processo applicativo
- La WebView espone un bridge diretto tra JS e PHP
- Le chiamate sono sincrone o asincrone, senza serializzazione manuale
La comunicazione avviene principalmente attraverso i Web Components PHP. Ogni componente è un elemento HTML lato JavaScript, è una classe PHP lato backend che espone metodi, proprietà, attributi ed eventi. Possiamo considerare un componente Boson come un oggetto condiviso tra JS e PHP. Il flusso tipico è il seguente:
- JavaScript invoca un metodo sul componente
- Boson intercetta la chiamata
- PHP riceve la chiamata e la gestisce
- PHP restituisce un valore (opzionale)
- JavaScript riceve il risultato
Tutto questo avviene senza fetch, endpoint, controller o router.
Invocare PHP da JavaScript
class Logger implements HasMethodsInterface
{
public function onMethodCalled(string $metodo, array $argomenti = []): mixed
{
if ($metodo === 'log') {
file_put_contents(
'app.log',
$argomenti[0] . PHP_EOL,
FILE_APPEND
);
}
return null;
}
public static function getMethodNames(): array
{
return ['log'];
}
}
// JavaScript
document.querySelector('logger-app').log('Evento dal browser');
PHP può restituire stringhe, numeri, array e ovviamente oggetti serializzabili
case 'datiUtente':
return [
'id' => 1,
'nome' => 'Mario',
'ruolo' => 'admin'
];
Lato JavaScript avremo invece:
const utente = servizio.datiUtente(); console.log(utente.nome);
Gestione dello stato applicativo
Per applicazioni complesse è utile centralizzare lo stato.
Contesto globale
class StatoApplicazione
{
private array $stato = [];
public function set(string $chiave, mixed $valore): void
{
$this->stato[$chiave] = $valore;
}
public function get(string $chiave): mixed
{
return $this->stato[$chiave] ?? null;
}
}
Questo oggetto può essere condiviso tra più componenti tramite dependency injection.
Deployment e distribuzione
Uno dei punti di forza di Boson PHP è la possibilità di distribuire un singolo eseguibile.
Il processo tipico include:
- Compilazione dell’applicazione
- Inclusione delle dipendenze PHP
- Packaging per il sistema operativo target
Il risultato è un file eseguibile che non richiede PHP installato sul sistema dell’utente finale.
Quando usare Boson PHP
Boson PHP è particolarmente adatto per:
- Applicazioni desktop leggere
- Tool interni aziendali
- Dashboard amministrative
- Client multipiattaforma per API
Non è pensato per sostituire framework web tradizionali, ma per affiancarli in contesti desktop.
Conclusione
Con Boson PHP, lo sviluppo desktop diventa un’estensione naturale dell’ecosistema PHP. Grazie ai Web Components nativi, alla comunicazione diretta con JavaScript e a un modello architetturale moderno, è possibile costruire applicazioni robuste, scalabili e manutenibili.
Nei prossimi articoli potremo approfondire:
- Testing dei componenti Boson
- Integrazione con Laravel o Symfony
- Gestione degli aggiornamenti automatici
- Performance e ottimizzazione
La serie Pulse Boson PHP continua.



