Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Zend Code Laravel Package

zendframework/zend-code

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation (via Composer):

    composer require zendframework/zend-code
    

    (Note: The package is now maintained as laminas/laminas-code; use that instead for new projects.)

  2. First Use Case: Generate a simple class dynamically:

    use Zend\Code\Generator\ClassGenerator;
    use Zend\Code\Generator\MethodGenerator;
    
    $class = new ClassGenerator('MyClass', 'MyNamespace');
    $method = new MethodGenerator('doSomething');
    $method->setBody('return "Hello, World!";');
    $class->addMethodFromGenerator($method);
    
    echo $class->generate();
    
  3. Key Classes to Explore:

    • ClassGenerator: For generating entire classes.
    • MethodGenerator: For generating methods.
    • PropertyGenerator: For generating properties.
    • ParameterGenerator: For generating method parameters.
    • ValueGenerator: For generating PHP values (e.g., arrays, strings).

Implementation Patterns

1. Dynamic Class Generation

Workflow: Generate classes at runtime (e.g., for proxies, DTOs, or dynamic APIs).

$class = new ClassGenerator('DynamicUser', 'App\\Entities');
$class->setExtendedClass('App\\BaseEntity');

$property = new PropertyGenerator('name', 'string');
$property->setVisibility('protected');
$class->addPropertyFromGenerator($property);

$method = new MethodGenerator('getFullName');
$method->setReturnType('string')
       ->setBody('return $this->name;');
$class->addMethodFromGenerator($method);

file_put_contents('DynamicUser.php', $class->generate());

2. Code Transformation

Workflow: Parse existing code, modify it, and regenerate.

use Zend\Code\Scanner\ClassScanner;

$scanner = new ClassScanner();
$reflection = $scanner->scanFile('ExistingClass.php');

// Modify a method
$method = $reflection->getMethod('existingMethod');
$method->setBody('// Updated logic: ' . $method->getBody());

// Regenerate the file
file_put_contents('ExistingClass.php', $reflection->generate());

3. DTO Generation

Pattern: Use ClassGenerator to create immutable DTOs.

$dtoClass = new ClassGenerator('UserDto', 'App\\Dto');
$dtoClass->setFinal(true);

$properties = [
    'id' => ['type' => 'int', 'visibility' => 'private'],
    'name' => ['type' => 'string', 'visibility' => 'private'],
];

foreach ($properties as $name => $config) {
    $property = new PropertyGenerator($name, $config['type']);
    $property->setVisibility($config['visibility']);
    $dtoClass->addPropertyFromGenerator($property);

    // Add getter
    $getter = new MethodGenerator('get' . ucfirst($name));
    $getter->setReturnType($config['type'])
           ->setBody('return $this->' . $name . ';');
    $dtoClass->addMethodFromGenerator($getter);
}

file_put_contents('UserDto.php', $dtoClass->generate());

4. Integration with Laravel

Pattern: Use for dynamic migrations, model generation, or API scaffolding.

// Example: Generate a migration file dynamically
$migration = new ClassGenerator('CreateUsersTable', 'Database\\Migrations');
$migration->setExtendedClass('Illuminate\\Database\\Migrations\\Migration');

$method = new MethodGenerator('up');
$method->setBody(
    '$table = $this->schema->create(\'users\', function ($table) { ' .
    '$table->id(); ' .
    '$table->string(\'name\'); ' .
    '$table->timestamps(); ' .
    '});'
);
$migration->addMethodFromGenerator($method);

file_put_contents(
    database_path('migrations/' . date('Y_m_d_His') . '_create_users_table.php'),
    $migration->generate()
);

5. Value Generation

Pattern: Generate complex PHP values (e.g., nested arrays, objects).

use Zend\Code\Generator\ValueGenerator;

$value = new ValueGenerator();
$value->addArrayItem('key1', 'value1');
$value->addArrayItem('key2', new ValueGenerator(['nested' => true]));

echo $value->generate(); // Outputs: ['key1' => 'value1', 'key2' => ['nested' => true]]

Gotchas and Tips

Pitfalls

  1. Namespace Handling:

    • Always set the namespace explicitly on ClassGenerator to avoid issues with fully qualified names.
    • Example:
      $class = new ClassGenerator('User', 'App\\Models');
      $class->setExtendedClass('App\\BaseModel'); // Correct
      $class->setExtendedClass('BaseModel');     // Incorrect (relative)
      
  2. Type Validation:

    • The package validates types strictly. Passing invalid types (e.g., 'foobar') will throw InvalidArgumentException.
    • Use TypeGenerator for complex types:
      $type = new TypeGenerator('App\\Models\\User[]');
      $method->setReturnType($type);
      
  3. PHP Version Compatibility:

    • The package supports PHP 7.1+. Features like void return types or nullable types (?string) require PHP 7.1+.
    • For PHP 7.0, omit these features or use fallbacks.
  4. DocBlock Generation:

    • DocBlocks are not added by default. Use DocBlockGenerator explicitly:
      $method->setDocBlock(new DocBlockGenerator('/** @return string */'));
      
  5. Method Overrides:

    • When copying methods with copyMethodSignature(), ensure the target class can actually override the method (e.g., visibility rules).
  6. Array Generation:

    • Short array syntax ([]) is used by default. To force long syntax (array()), configure ValueGenerator:
      $value = new ValueGenerator();
      $value->setUseShortArraySyntax(false);
      

Debugging Tips

  1. Inspect Generated Code:

    • Use $generator->generate() to preview code before writing to a file.
    • Example:
      echo $class->generate(); // Debug output
      
  2. Scanner Limitations:

    • The ClassScanner may not handle all edge cases (e.g., complex closures, dynamic code). For robust parsing, consider combining with PHPParser.
    • Example workaround:
      use PhpParser\ParserFactory;
      $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
      $code = file_get_contents('file.php');
      $stmts = $parser->parse($code);
      
  3. Visibility Issues:

    • If methods/properties aren’t appearing, check:
      • Visibility is set correctly (public, protected, private).
      • The generator’s addMethodFromGenerator() is used (not addMethod() for raw strings).
  4. Performance:

    • Generating large classes (e.g., with 100+ methods) can be slow. Cache generated code if reused:
      $cache = file_get_contents('cache/class_cache.json');
      if ($cache) {
          $class = json_decode($cache, true);
      } else {
          $class = (new ClassGenerator('LargeClass'))->addMethods(...);
          file_put_contents('cache/class_cache.json', json_encode($class->generate()));
      }
      

Extension Points

  1. Custom Generators:

    • Extend AbstractGenerator to create domain-specific generators (e.g., for SQL, YAML).
    • Example:
      class SqlGenerator extends AbstractGenerator {
          public function generate() { /* Custom logic */ }
      }
      
  2. Scanner Extensions:

    • Override ClassScanner to handle custom syntax (e.g., annotations, traits).
    • Example:
      class CustomScanner extends ClassScanner {
          protected function scanAnnotations() { /* Custom logic */ }
      }
      
  3. ValueGenerator Hooks:

    • Extend ValueGenerator to support custom value types (e.g., DateTime objects):
      $value = new ValueGenerator();
      $value->addValue(new CustomValueGenerator(new \DateTime()));
      
  4. Integration with Laravel:

    • Use service providers to bind generators for DI:
      $this->app->bind('code-generator', function () {
          return new ClassGenerator();
      });
      
    • Create a facade for convenience:
      class CodeGeneratorFacade extends Facade {
          protected static function getFacadeAccessor() { return 'code-generator'; }
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor
spatie/laravel-javascript-views