What Is the `php_` C++ Symbol Prefix in TypePHP?

In TypePHP, the php_ prefix designates the C++ ABI for symbols that correspond to user-defined PHP functions and class methods, ensuring stable, collision-free entry points between the PHP runtime and compiled C++ code.

The swoole/typephp compiler transforms PHP source into native C++ to improve execution performance, but this translation requires callable entry points that the PHP engine can invoke without name conflicts. The php_ prefix serves as the exclusive namespace for these user-facing symbols, distinguishing them from internal runtime helpers and Zend API wrappers.

The php_ Prefix and TypePHP's Symbol Architecture

TypePHP employs a strict naming convention to separate concerns across its codebase. While internal runtime logic uses the typephp_ prefix and Zend API wrappers reside under php::, the compiler reserves php_ specifically for symbols that originate from PHP declarations.

When the compiler processes a PHP function or method, it normalizes the namespace, class, and function identifiers, then joins them with double underscores (__). For example, a function greet in namespace App becomes php_app__greet in the generated C++.

Comparison of Prefix Scopes

Prefix Scope Example Visibility
typephp_ Runtime internals typephp_call_parent_constructor() Internal
php:: PHPX Zend API wrapper php::deindirect() API
php_ User PHP callable php_app__greet() Linker-visible

How TypeCPP Generates php_ Symbols

The transformation from PHP to C++ follows a predictable pattern defined in the project's documentation and compiler core. For global functions, the compiler emits a C++ function with the php_ prefix followed by the normalized path.

Given this PHP source:

namespace App;

function hello(string $msg): void {}

class Logger {
    public function log(string $msg): void {}
}

The compiler generates these C++ signatures in the resulting translation unit:

// Function – global callable
void php_app__hello(php::Str msg);

// Method – instance callable (first param is $this)
void php_app__logger__log(php::Object &this_, php::Str msg);

Instance methods receive the object as the first parameter (this_), while static methods and functions follow the standard calling convention.

Why TypePHP Reserves the php_ Prefix

The dedication of php_ to user-declared symbols serves three critical architectural goals according to the swoole/typephp source code:

  1. Collision Avoidance – By restricting php_ to user code, TypePHP prevents global helpers from clashing with compiled PHP functions. A user-defined function deindirect() maps to php_deindirect, ensuring it never conflicts with internal typephp_ helpers.

  2. Consistent ABI – All generated stubs share the same naming format and calling convention. This stability allows the stub generator, runtime library, and external C++ consumers to rely on a version-stable interface.

  3. Linker Visibility – Because php_ symbols are exposed to the linker, the PHP engine can dynamically resolve and invoke them when executing user code.

Implementation in the TypePHP Compiler

The enforcement of this prefix convention begins in src/CompilerBase.php, where the compiler defines the constant used during code generation:

public const string PREFIX = 'php_';

This constant drives the symbol naming logic throughout the compilation pipeline. The comprehensive specification for these rules lives in docs/zh-cn/CPP_SYMBOL_NAMING.md, which documents the ABI requirements for generated stubs.

When the compiler emits C++ for a class method like App\User::save(), it constructs the symbol php_app__user__save, making it immediately callable by the runtime's invocation handlers.

Summary

  • The php_ prefix marks C++ symbols that expose user-defined PHP functions and methods to the runtime.
  • TypePHP generates these symbols by joining normalized PHP identifiers with double underscores (e.g., php_app__greet).
  • This convention prevents naming collisions with internal typephp_ helpers and Zend API wrappers.
  • The prefix is defined as the PREFIX constant in src/CompilerBase.php.
  • All php_ symbols are linker-visible, enabling dynamic resolution by the PHP engine.

Frequently Asked Questions

What does the php_ prefix represent in TypePHP?

It represents the C++ ABI boundary for user-declared PHP functions and class methods. The prefix distinguishes compiled PHP entry points from TypePHP's internal runtime functions and PHPX wrapper utilities, ensuring that only user code occupies this namespace.

How does TypePHP handle PHP namespaces when generating php_ symbols?

The compiler normalizes namespace separators and class names into a flat structure using double underscores. For instance, App\Controller\Base::index() becomes php_app__controller__base__index, ensuring unique, predictable symbol names across the codebase that the linker can resolve.

Why doesn't TypePHP use the typephp_ prefix for user functions?

The typephp_ namespace is reserved for the compiler's internal runtime logic and helper functions. Separating user symbols under php_ guarantees that internal refactors never break the public ABI exposed to the PHP engine, maintaining backward compatibility for compiled extensions.

Where can I find the official documentation for TypePHP's C++ naming conventions?

The specification resides in docs/zh-cn/CPP_SYMBOL_NAMING.md within the swoole/typephp repository. This document details the mapping between PHP declarations and their corresponding php_ C++ symbols, including the double-underscore separator rules and method signatures.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →