Auto-generated from project constitution. Last updated: 2025-11-18
PHP Script is a JavaScript-inspired scripting language that runs entirely in PHP, enabling end-users to customize and extend PHP-powered backends without requiring a separate Node.js service. It provides a secure, sandboxed execution environment with full control over exposed functions and data.
- PHP 8.4+ + None (PHP-native, following Zero External Dependencies principle) (001-break-continue)
- N/A (language feature, no data persistence) (001-break-continue)
- Language: PHP 8.4+
- Testing: PEST (PHP Testing Framework)
- Static Analysis: PHPStan (maximum strictness level)
- Code Style: Laravel Pint (PSR-12 compliant)
- Refactoring: Rector
- Editor Integration: Monaco Editor
- Documentation: Jekyll (GitHub Pages)
- No external runtime dependencies (PHP-native)
- Composer for development tools only
- Monaco Editor for playground/integration
php-script/
├── src/
│ ├── Core/ # Core engine components
│ │ ├── Engine.php # Main orchestrator
│ │ ├── Lexer.php # Tokenization
│ │ ├── Parser.php # AST generation
│ │ ├── AstTraverser.php # Execution engine
│ │ └── PhpScriptRenderer.php # Code generation
│ ├── Ast/ # AST node definitions
│ │ ├── BaseNode.php
│ │ ├── Program.php
│ │ ├── Statements/ # Statement nodes
│ │ ├── Expressions/ # Expression nodes
│ │ └── Terminals/ # Leaf nodes
│ ├── Contracts/ # Interfaces
│ │ ├── LexerInterface.php
│ │ ├── ParserInterface.php
│ │ ├── AstTraverserInterface.php
│ │ └── Node.php
│ ├── Exceptions/ # Custom exceptions
│ │ ├── LexerException.php
│ │ ├── ParseException.php
│ │ ├── AstTraverserException.php
│ │ └── EngineException.php
│ ├── Linter/ # Code validation
│ │ └── LinterService.php
│ └── Monarch/ # Monaco Editor integration
│ └── MonarchLanguageDefinitionService.php
├── tests/ # Mirror of src/ structure
├── docs/ # Jekyll documentation site
│ ├── language/ # Language reference
│ └── php/ # Integration guides
├── public/ # Playground demo
│ └── playground.php
├── .specify/ # Speckit framework integration
│ ├── commands/ # Slash commands (in .claude/commands/)
│ ├── memory/
│ │ └── constitution.md # Project constitution
│ ├── scripts/ # Workflow automation
│ │ ├── check-prerequisites.sh
│ │ ├── create-new-feature.sh
│ │ ├── setup-plan.sh
│ │ └── update-agent-context.sh
│ └── templates/ # Document templates
│ ├── spec-template.md
│ ├── plan-template.md
│ ├── tasks-template.md
│ ├── checklist-template.md
│ └── agent-file-template.md
└── specs/ # Feature specifications (created per-feature)
└── NNN-feature-name/ # Numbered feature directories
├── spec.md # Feature specification
├── plan.md # Implementation plan
├── tasks.md # Task breakdown
└── research.md # Research notes
# ALWAYS run in this order before committing:
# 1. Fix code style
composer lint
# 2. Apply automated refactorings
composer refactor
# 3. Re-lint (refactoring can introduce style issues)
composer lint
# 4. Run full test suite (includes all checks below)
composer test# Test coverage (must be 100%)
composer test:unit
# Type coverage (must be 100%)
composer test:type-coverage
# Static analysis (zero errors)
composer test:types
# Code style check (zero errors)
composer test:lint
# Refactoring check (zero violations)
composer test:refactor# Start playground demo
make playground # → http://localhost:8080/playground.php
# Watch mode for development
composer test:watchThe project uses the Speckit framework for structured feature development:
# Create a new feature specification
/speckit.specify <feature description>
# Generate implementation plan
/speckit.plan
# Generate task breakdown
/speckit.tasks
# Analyze consistency across artifacts
/speckit.analyze
# Execute implementation
/speckit.implement
# Update project constitution
/speckit.constitution
# Generate custom checklist
/speckit.checklist
# Clarify underspecified areas
/speckit.clarify
# Convert tasks to GitHub issues
/speckit.taskstoissues-
100% Test Coverage - Every line must be tested
- Enforced via PEST with coverage verification
- No exceptions, no baselines
-
100% Type Coverage - Every property and method fully typed
- Enforced via PEST type-coverage plugin
declare(strict_types=1);in all files
-
Zero Linting Errors - PSR-12 compliance via Laravel Pint
- Custom rules in pint.json
- Auto-fix available but must verify
-
Zero Static Analysis Errors - PHPStan at maximum level
- Configuration in phpstan.neon.dist
- No baseline files allowed
-
Zero Refactoring Violations - Rector rules enforcement
- Configuration in rector.php
- Auto-refactor available but must verify
Never commit until ALL five pillars pass. No exceptions.
- Classes: PascalCase, singular nouns (
Engine,Parser,BinaryOperation) - Methods: camelCase, verb-based (
execute(),allowFunction(),setContext()) - Variables: camelCase, descriptive (
$executionTimeLimit,$allowedFunctions) - Constants: SCREAMING_SNAKE_CASE (
TOKEN_TYPE_IDENTIFIER)
- One Class Per File - Filename matches class name
- Strict Types - Always
declare(strict_types=1);at top - Final by Default - Classes are final unless designed for extension
- Readonly Properties - Use readonly when possible
- Constructor Property Promotion - Preferred for simple properties
- Fail Fast - Throw exceptions early
- Specific Exceptions - Use appropriate exception types from src/Exceptions/
- Helpful Messages - Include context and suggestions
- Source Pointers - Always include line/column information for user-facing errors
PHP Script is designed as a sandboxed execution environment:
- No Eval - No dynamic code execution
- No File System - No file operations
- No Network - No HTTP/socket access
- Explicit Whitelisting - Functions must be explicitly allowed via
Engine->allow() - Context Control - Variables must be explicitly set via
Engine->set() - Time Limits - Execution timeouts available via
setExecutionTimeLimit()
All core services are defined by interfaces in src/Contracts/:
- Enables dependency injection
- Facilitates testing with mocks
- Allows alternative implementations
- Enforces clear separation of concerns
Execution follows a clear pipeline:
Source Code → Lexer → Tokens → Parser → AST → AstTraverser → Result
Each stage:
- Has its own dedicated class
- Implements a specific contract
- Throws specific exception types
- Is independently testable
The language syntax is designed to be immediately recognizable to JavaScript developers:
// Variable assignment (no var/let/const)
x = 10
name = 'John'
// String concatenation
message = 'Hello ' + name
// Comments (single-line only)
// This is a comment
// Control flow
if (x > 5) {
echo 'Large'
} else {
echo 'Small'
}
for (i = 0; i < 10; i = i + 1) {
echo i
}
foreach (items as item) {
echo item
}While syntax is JS-like, data types are PHP-native:
- Object property access:
user.name - Method calls:
user.hasPermission('admin') - Array access:
users_list[0] - All PHP types supported: strings, integers, floats, booleans, arrays, objects
The project provides comprehensive Monaco Editor integration via MonarchLanguageDefinitionService:
- Syntax Highlighting - Token classification for keywords, operators, strings, numbers, comments
- Code Completion - Dynamic suggestions based on:
- Variables from
Engine->set() - Allowed functions from
Engine->allow() - Object properties and methods (introspected from context)
- Control flow snippets (for, foreach, if, ifelse)
- Variables from
- Linting - Real-time validation via
LinterService - Error Messages - Precise source locations for errors
- Located in
public/playground.php - Run with
make playground - Access at http://localhost:8080/playground.php
- Full working example of Monaco integration
- 001-break-continue: Added PHP 8.4+ + None (PHP-native, following Zero External Dependencies principle)
- Added 9 slash commands for structured feature development workflow
- Created
.specify/directory structure with scripts, templates, and memory
Tests mirror the src/ structure:
tests/Core/- Core component teststests/Ast/- AST node teststests/Linter/- Linting service teststests/Monarch/- Monaco integration tests
- Comprehensive Coverage - 100% line and branch coverage required
- Behavior Testing - Test functionality, not implementation
- Edge Cases - Explicitly test error conditions and boundaries
- Clear Naming - Test names describe what they verify (PEST's
it()style) - Isolated Tests - No dependencies between tests
it('executes a simple echo statement', function () {
$engine = new Engine();
$result = $engine->execute("echo 'Hello World'");
expect($result)->toBe('Hello World');
});
it('throws exception for undefined variable', function () {
$engine = new Engine();
$engine->execute("echo undefined_var");
})->throws(AstTraverserException::class);- main - Production-ready code
- Feature branches - For Speckit workflow, use format:
NNN-feature-name(e.g.,001-add-while-loops) - PR Required - All changes must go through pull request review
- Clear, descriptive summaries
- Explain "why" in body if non-obvious
- Reference issues where applicable
- Conventional commits encouraged
Before merging:
- ✓ All tests pass (GitHub Actions)
- ✓ 100% code coverage maintained
- ✓ 100% type coverage maintained
- ✓ Code review approved
- ✓ Documentation updated if applicable
PHP Script is designed for scenarios where:
- End-users need limited scripting capabilities
- Full PHP access would be dangerous
- A separate Node.js service is not desired
- Fine-grained control over available functions is required
- Sandboxing - No access to PHP's global functions or filesystem
- Whitelisting - Functions must be explicitly allowed via
Engine->allow() - Context Control - Only explicitly set variables are accessible via
Engine->set() - Time Limits - Execution timeouts prevent infinite loops
- No Dynamic Execution - No eval(), no dynamic includes, no code generation
⚠️ Never expose dangerous functions (file operations, exec, eval, etc.)⚠️ Validate and sanitize all data before passing to context⚠️ Use execution time limits for untrusted scripts⚠️ Review all exposed object methods for security implications⚠️ Consider the blast radius of each exposed function
- DocBlocks required for all public methods, complex private methods, classes, and interfaces
- Type hints - Always use PHP 8.4 native type hints (prefer over docblock types)
- Comments - Explain "why", not "what" (code should be self-documenting)
Jekyll-based site in docs/:
docs/language/- PHP Script language referencedocs/php/- PHP integration guides- Hosted via GitHub Pages
When adding features, update:
- Relevant
docs/language/files - Examples in
docs/php/guides - README.md if user-facing
- Consider adding playground examples
PHP Script was created by Robert Kummer ([email protected])
- License: MIT License
- Repository: https://github.com/php-script/php-script
- Maintainer: Robert Kummer
This file is generated from .specify/memory/constitution.md, which is the authoritative source for project principles and standards.
When in doubt, consult the constitution. When the constitution conflicts with code, the constitution wins (fix the code, not the constitution—unless the principle itself needs to change via explicit constitutional update).
Last Updated: 2025-11-18 Constitution Version: 1.0.0 Generated By: Speckit Framework Integration