Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 65 additions & 13 deletions docs/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,25 +81,77 @@ While the first point speaks for itself, the second may be harder to apprehend.

While some variable types have the same memory representation between C/PHP and Go, some types require more logic to be directly used. This is maybe the hardest part when it comes to writing extensions because it requires understanding internals of the Zend Engine and how variables are stored internally in PHP. This table summarizes what you need to know:

| PHP type | Go type | Direct conversion | C to Go helper | Go to C helper | Class Methods Support |
|--------------------|------------------|-------------------|-----------------------|------------------------|-----------------------|
| `int` | `int64` | ✅ | - | - | ✅ |
| `?int` | `*int64` | ✅ | - | - | ✅ |
| `float` | `float64` | ✅ | - | - | ✅ |
| `?float` | `*float64` | ✅ | - | - | ✅ |
| `bool` | `bool` | ✅ | - | - | ✅ |
| `?bool` | `*bool` | ✅ | - | - | ✅ |
| `string`/`?string` | `*C.zend_string` | ❌ | frankenphp.GoString() | frankenphp.PHPString() | ✅ |
| `array` | `slice`/`map` | ❌ | _Not yet implemented_ | _Not yet implemented_ | ❌ |
| `object` | `struct` | ❌ | _Not yet implemented_ | _Not yet implemented_ | ❌ |
| PHP type | Go type | Direct conversion | C to Go helper | Go to C helper | Class Methods Support |
|--------------------|---------------------|-------------------|-----------------------|------------------------|-----------------------|
| `int` | `int64` | ✅ | - | - | ✅ |
| `?int` | `*int64` | ✅ | - | - | ✅ |
| `float` | `float64` | ✅ | - | - | ✅ |
| `?float` | `*float64` | ✅ | - | - | ✅ |
| `bool` | `bool` | ✅ | - | - | ✅ |
| `?bool` | `*bool` | ✅ | - | - | ✅ |
| `string`/`?string` | `*C.zend_string` | ❌ | frankenphp.GoString() | frankenphp.PHPString() | ✅ |
| `array` | `*frankenphp.Array` | ❌ | frankenphp.GoArray() | frankenphp.PHPArray() | ✅ |
| `object` | `struct` | ❌ | _Not yet implemented_ | _Not yet implemented_ | ❌ |

> [!NOTE]
> This table is not exhaustive yet and will be completed as the FrankenPHP types API gets more complete.
>
> For class methods specifically, only primitive types are currently supported. Arrays and objects cannot be used as method parameters or return types yet.
> For class methods specifically, primitive types and arrays are currently supported. Objects cannot be used as method parameters or return types yet.

If you refer to the code snippet of the previous section, you can see that helpers are used to convert the first parameter and the return value. The second and third parameter of our `repeat_this()` function don't need to be converted as memory representation of the underlying types are the same for both C and Go.

#### Working with Arrays

FrankenPHP provides native support for PHP arrays through the `frankenphp.Array` type. This type represents both PHP indexed arrays (lists) and associative arrays (hashmaps) with ordered key-value pairs.

**Creating and manipulating arrays in Go:**

```go
//export_php:function process_data(array $input): array
func process_data(arr *C.zval) unsafe.Pointer {
// Convert PHP array to Go
goArray := frankenphp.GoArray(unsafe.Pointer(arr))

result := &frankenphp.Array{}

result.SetInt(0, "first")
result.SetInt(1, "second")
result.Append("third") // Automatically assigns next integer key

result.SetString("name", "John")
result.SetString("age", int64(30))

for i := uint32(0); i < goArray.Len(); i++ {
key, value := goArray.At(i)
if key.Type == frankenphp.PHPStringKey {
result.SetString("processed_"+key.Str, value)
} else {
result.SetInt(key.Int+100, value)
}
}

// Convert back to PHP array
return frankenphp.PHPArray(result)
}
```

**Key features of `frankenphp.Array`:**

* **Ordered key-value pairs** - Maintains insertion order like PHP arrays
* **Mixed key types** - Supports both integer and string keys in the same array
* **Type safety** - The `PHPKey` type ensures proper key handling
* **Automatic list detection** - When converting to PHP, automatically detects if array should be a packed list or hashmap
* **Objects are not supported** - Currently, only scalar types and arrays can be used as values. Providing an object will result in a `null` value in the PHP array.

**Available methods:**

* `SetInt(key int64, value interface{})` - Set value with integer key
* `SetString(key string, value interface{})` - Set value with string key
* `Append(value interface{})` - Add value with next available integer key
* `Len() uint32` - Get number of elements
* `At(index uint32) (PHPKey, interface{})` - Get key-value pair at index
* `frankenphp.PHPArray(arr *frankenphp.Array) unsafe.Pointer` - Convert to PHP array

### Declaring a Native PHP Class

The generator supports declaring **opaque classes** as Go structs, which can be used to create PHP objects. You can use the `//export_php:class` directive comment to define a PHP class. For example:
Expand Down Expand Up @@ -188,7 +240,7 @@ func (us *UserStruct) UpdateInfo(name *C.zend_string, age *int64, active *bool)
* **PHP `null` becomes Go `nil`** - when PHP passes `null`, your Go function receives a `nil` pointer

> [!WARNING]
> Currently, class methods have the following limitations. **Arrays and objects are not supported** as parameter types or return types. Only scalar types are supported: `string`, `int`, `float`, `bool` and `void` (for return type). **Nullable parameter types are fully supported** for all scalar types (`?string`, `?int`, `?float`, `?bool`).
> Currently, class methods have the following limitations. **Objects are not supported** as parameter types or return types. **Arrays are fully supported** for both parameters and return types. Supported types: `string`, `int`, `float`, `bool`, `array`, and `void` (for return type). **Nullable parameter types are fully supported** for all scalar types (`?string`, `?int`, `?float`, `?bool`).

After generating the extension, you will be allowed to use the class and its methods in PHP. Note that you **cannot access properties directly**:

Expand Down
78 changes: 65 additions & 13 deletions docs/fr/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,25 +81,77 @@ Alors que le premier point parle de lui-même, le second peut être plus diffici

Bien que certains types de variables aient la même représentation mémoire entre C/PHP et Go, certains types nécessitent plus de logique pour être directement utilisés. C'est peut-être la partie la plus difficile quand il s'agit d'écrire des extensions car cela nécessite de comprendre les fonctionnements internes du moteur Zend et comment les variables sont stockées dans le moteur de PHP. Ce tableau résume ce que vous devez savoir :

| Type PHP | Type Go | Conversion directe | Assistant C vers Go | Assistant Go vers C | Support des Méthodes de Classe |
|--------------------|------------------|--------------------|-------------------------|-------------------------|--------------------------------|
| `int` | `int64` | ✅ | - | - | ✅ |
| `?int` | `*int64` | ✅ | - | - | ✅ |
| `float` | `float64` | ✅ | - | - | ✅ |
| `?float` | `*float64` | ✅ | - | - | ✅ |
| `bool` | `bool` | ✅ | - | - | ✅ |
| `?bool` | `*bool` | ✅ | - | - | ✅ |
| `string`/`?string` | `*C.zend_string` | ❌ | frankenphp.GoString() | frankenphp.PHPString() | ✅ |
| `array` | `slice`/`map` | ❌ | _Pas encore implémenté_ | _Pas encore implémenté_ | |
| `object` | `struct` | ❌ | _Pas encore implémenté_ | _Pas encore implémenté_ | ❌ |
| Type PHP | Type Go | Conversion directe | Assistant C vers Go | Assistant Go vers C | Support des Méthodes de Classe |
|--------------------|---------------------|--------------------|-------------------------|-------------------------|--------------------------------|
| `int` | `int64` | ✅ | - | - | ✅ |
| `?int` | `*int64` | ✅ | - | - | ✅ |
| `float` | `float64` | ✅ | - | - | ✅ |
| `?float` | `*float64` | ✅ | - | - | ✅ |
| `bool` | `bool` | ✅ | - | - | ✅ |
| `?bool` | `*bool` | ✅ | - | - | ✅ |
| `string`/`?string` | `*C.zend_string` | ❌ | frankenphp.GoString() | frankenphp.PHPString() | ✅ |
| `array` | `*frankenphp.Array` | ❌ | frankenphp.GoArray() | frankenphp.PHPArray() | |
| `object` | `struct` | ❌ | _Pas encore implémenté_ | _Pas encore implémenté_ | ❌ |

> [!NOTE]
> Ce tableau n'est pas encore exhaustif et sera complété au fur et à mesure que l'API de types FrankenPHP deviendra plus complète.
>
> Pour les méthodes de classe spécifiquement, seuls les types primitifs sont actuellement supportés. Les tableaux et objets ne peuvent pas encore être utilisés comme paramètres de méthode ou types de retour.
> Pour les méthodes de classe spécifiquement, les types primitifs et les tableaux sont supportés. Les objets ne peuvent pas encore être utilisés comme paramètres de méthode ou types de retour.

Si vous vous référez à l'extrait de code de la section précédente, vous pouvez voir que des assistants sont utilisés pour convertir le premier paramètre et la valeur de retour. Les deuxième et troisième paramètres de notre fonction `repeat_this()` n'ont pas besoin d'être convertis car la représentation mémoire des types sous-jacents est la même pour C et Go.

#### Travailler avec les Tableaux

FrankenPHP fournit un support natif pour les tableaux PHP à travers le type `frankenphp.Array`. Ce type représente à la fois les tableaux indexés PHP (listes) et les tableaux associatifs (hashmaps) avec des paires clé-valeur ordonnées.

**Créer et manipuler des tableaux en Go :**

```go
//export_php:function process_data(array $input): array
func process_data(arr *C.zval) unsafe.Pointer {
// Convertir le tableau PHP vers Go
goArray := frankenphp.GoArray(unsafe.Pointer(arr))

result := &frankenphp.Array{}

result.SetInt(0, "first")
result.SetInt(1, "second")
result.Append("third") // Assigne automatiquement la prochaine clé entière

result.SetString("name", "John")
result.SetString("age", int64(30))

for i := uint32(0); i < goArray.Len(); i++ {
key, value := goArray.At(i)
if key.Type == frankenphp.PHPStringKey {
result.SetString("processed_"+key.Str, value)
} else {
result.SetInt(key.Int+100, value)
}
}

// Reconvertir vers un tableau PHP
return frankenphp.PHPArray(result)
}
```

**Fonctionnalités clés de `frankenphp.Array` :**

* **Paires clé-valeur ordonnées** - Maintient l'ordre d'insertion comme les tableaux PHP
* **Types de clés mixtes** - Supporte les clés entières et chaînes dans le même tableau
* **Sécurité de type** - Le type `PHPKey` assure une gestion appropriée des clés
* **Détection automatique de liste** - Lors de la conversion vers PHP, détecte automatiquement si le tableau doit être une liste compacte ou un hashmap
* **Les objets ne sont pas supportés** - Actuellement, seuls les types scalaires et les tableaux sont supportés. Passer un objet en tant qu'élément du tableau résultera d'une valeur `null` dans le tableau PHP.

**Méthodes disponibles :**

* `SetInt(key int64, value interface{})` - Définir une valeur avec une clé entière
* `SetString(key string, value interface{})` - Définir une valeur avec une clé chaîne
* `Append(value interface{})` - Ajouter une valeur avec la prochaine clé entière disponible
* `Len() uint32` - Obtenir le nombre d'éléments
* `At(index uint32) (PHPKey, interface{})` - Obtenir la paire clé-valeur à l'index
* `frankenphp.PHPArray(arr *frankenphp.Array) unsafe.Pointer` - Convertir vers un tableau PHP

### Déclarer une Classe PHP Native

Le générateur prend en charge la déclaration de **classes opaques** comme structures Go, qui peuvent être utilisées pour créer des objets PHP. Vous pouvez utiliser la directive `//export_php:class` pour définir une classe PHP. Par exemple :
Expand Down Expand Up @@ -188,7 +240,7 @@ func (us *UserStruct) UpdateInfo(name *C.zend_string, age *int64, active *bool)
* **PHP `null` devient Go `nil`** - quand PHP passe `null`, votre fonction Go reçoit un pointeur `nil`

> [!WARNING]
> Actuellement, les méthodes de classe ont les limitations suivantes. **Les tableaux et objets ne sont pas supportés** comme types de paramètres ou types de retour. Seuls les types scalaires sont supportés : `string`, `int`, `float`, `bool` et `void` (pour le type de retour). **Les types de paramètres nullables sont entièrement supportés** pour tous les types scalaires (`?string`, `?int`, `?float`, `?bool`).
> Actuellement, les méthodes de classe ont les limitations suivantes. **Les objets ne sont pas supportés** comme types de paramètres ou types de retour. **Les tableaux sont entièrement supportés** pour les paramètres et types de retour. Types supportés : `string`, `int`, `float`, `bool`, `array`, et `void` (pour le type de retour). **Les types de paramètres nullables sont entièrement supportés** pour tous les types scalaires (`?string`, `?int`, `?float`, `?bool`).

Après avoir généré l'extension, vous serez autorisé à utiliser la classe et ses méthodes en PHP. Notez que vous **ne pouvez pas accéder aux propriétés directement** :

Expand Down
Loading
Loading