Giter Site home page Giter Site logo

laminas / laminas-code Goto Github PK

View Code? Open in Web Editor NEW
1.8K 23.0 78.0 4.74 MB

Extensions to the PHP Reflection API, static code scanning, and code generation

Home Page: https://docs.laminas.dev/laminas-code/

License: BSD 3-Clause "New" or "Revised" License

PHP 100.00%
code-generation code-scanning reflection-api

laminas-code's Introduction

laminas-code

Continuous Integration Type Coverage

🇷🇺 Русским гражданам

Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как в России, так и в Украине. Некоторые из нас родились в России. Некоторые из нас живут в России. У некоторых бабушки и дедушки сражались с фашистами во Второй мировой войне. Здесь никто не поддерживает фашизм.

У одного из нас есть украинская родственница, которая спаслась из дома вместе с сыном. Поезд задержался из-за бомбежки на дороге впереди. У нас есть друзья, которые прячутся в бомбоубежищах. Мы с тревогой ждем весточки от них после воздушных налетов, которые беспорядочно наносят удары и попадают по больницам, школам, детским садам и домам. Мы не берем это из каких-либо СМИ. Мы наблюдаем это напрямую.

Вы доверяете нам достаточно, чтоб использовать наши программы, и мы просим вас довериться нам вновь. Мы нуждаемся в помощи. Выходите и протестуйте против этой бесполезной войны. Остановите кровопролитие. Скажите "Нет войне!"

🇺🇸 To Citizens of Russia

We at Laminas come from all over the world. Many of us have friends, family and colleagues in both Russia and Ukraine. Some of us were born in Russia. Some of us currently live in Russia. Some have grandparents who fought Nazis in World War II. Nobody here supports fascism.

One team member has a Ukrainian relative who fled her home with her son. The train was delayed due to bombing on the road ahead. We have friends who are hiding in bomb shelters. We anxiously follow up on them after the air raids, which indiscriminately fire at hospitals, schools, kindergartens and houses. We're not taking this from any media. These are our actual experiences.

You trust us enough to use our software. We ask that you trust us to say the truth on this. We need your help. Go out and protest this unnecessary war. Stop the bloodshed. Say "stop the war!"

Laminas\Code\Generator provides facilities to generate arbitrary code using an object-oriented interface, both to create new code as well as to update existing code. While the current implementation is limited to generating PHP code, you can easily extend the base class in order to provide code generation for other tasks: JavaScript, configuration files, apache vhosts, etc.

laminas-code's People

Contributors

akrabat avatar allansun avatar bakura10 avatar basz avatar blanchonvincent avatar dasprid avatar evandotpro avatar ezimuel avatar freeaqingme avatar ionbazan avatar laminas-bot avatar localheinz avatar maks3w avatar marc-mabe avatar mchekin avatar michalbundyra avatar mikaelkael avatar mwillbanks avatar neeckeloo avatar ocramius avatar padraic avatar prolic avatar ralphschindler avatar renovate[bot] avatar samsonasik avatar sgehrig avatar steverhoades avatar thinkscape avatar vahid-sohrabloo avatar weierophinney avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laminas-code's Issues

[BC Break] Drop built-in code scanners for 4.0

There is a discussion in the PR #123 about possible removing of low-level scanners in the Zend\Code\Scanner subnamespace for 4.0. Reason for that is to avoid keeping support for low-level code analysis via tokens inside scanners, this job can be performed by external libraries, such as nikic/php-parser, roave/better-reflection, goaop/parser-reflection, etc.

Some facts about Scanner code usage in the project zendframework/zend-code#123 (comment):

  • There are only dependencies on Scanner namespace in the Reflection namespace, eg. Zend\Code\Reflection\DocBlockReflection::reflect uses DocBlockScanner class, as well Zend\Code\Reflection\FileReflection::reflect uses CachingFileScanner. All remaining integration parts could be removed as they unused.
  • Classes from the Reflection namespace adds some public API to the PHP internal classes, thus Reflection namespace could not be easily dropped if we want to support *Generator::fromReflection() methods that accept only Zend\Code\Reflection classes and use specific methods from reflection.
  • If we decide to drop fromReflection() method from all generators or replace typehint in them with built-in PHP classes, then whole Scanner and Reflection namespace could be dropped, but it will be significant BC break as we remove all functionality that are not related directly to the code generation.

@Ocramius suggestions from zendframework/zend-code#123 (comment):

Whole Scanner namespace could be removed, there are only dependencies in Reflection namespace, eg. Zend\Code\Reflection\DocBlockReflection::reflect uses DocBlockScanner class, as well Zend\Code\Reflection\FileReflection::reflect uses CachingFileScanner. All remaining integration parts could be removed as they unused.

Yeah, this stuff can be dropped. At this point, pointing to roave/better-reflection for most of the "brute-forcing the filesystem, looking for symbols"

Classes from the Reflection namespace adds some public API to the PHP internal classes, thus Reflection namespace could not be easily dropped if we want to support *Generator::fromReflection() methods that accept only Zend\Code\Reflection classes and use specific methods from reflection.

Not sure about this one. I think the initial idea was that ext-reflection had huge potholes, and the library tried to fill them. I'd keep this for a separate issue, to figure out if the Zend\Code\Reflection namespace actually does anything more than ext-reflection these days. Considering that Zend\Code\Reflection is the entry point to all of the usages of this library (including the generators), I think that would make the migration path too painful at first.

If we decide to drop fromReflection() method from all generators or replace typehint in them with built-in PHP classes, then whole Scanner and Reflection namespace could be dropped, but it will be significant BC break as we remove all functionality that are not related directly to the code generation.

The ::fromReflection() constructors are extremely useful to mimick API without rewriting all of it manually, so I'd probably keep them in place. Instead, I think that allowing core reflection classes as parameters would be a better solution here.

I like the idea to drop both Scanner and Reflection namespaces from the code.

Let's start with the Scanner only for now.


Originally posted by @lisachenko at zendframework/zend-code#155

v3 only: Unknown Notices from ClassScanner

Notice: Undefined offset: 585 in /var/www/.../current/vendor/zendframework/zend-code/src/Scanner/ClassScanner.php on line 939

Notice: Uninitialized string offset: 1 in /var/www/.../current/vendor/zendframework/zend-code/src/Scanner/ClassScanner.php on line 971

Notice: Uninitialized string offset: 1 in /var/www/.../current/vendor/zendframework/zend-code/src/Scanner/ClassScanner.php on line 971

Notice: Uninitialized string offset: 1 in /var/www/.../current/vendor/zendframework/zend-code/src/Scanner/ClassScanner.php on line 971

Notice: Undefined offset: 267 in /var/www/.../current/vendor/zendframework/zend-code/src/Scanner/ClassScanner.php on line 939

BTW: I just added a new directory to scan via the great zend annotation module but it fails with a fatal exception in the ClassScanner. Is it possible to add more accurate error messages which make it simple to locate the file?

edit:

  • Error when folder contains empty file.
  • Notice:
Notice: Uninitialized string offset: 1 in /var/www/.../current/vendor/zendframework/zend-code/src/Scanner/TokenArrayScanner.php on line 582 Notice: Uninitialized string offset: 1 in /var/www/.../current/vendor/zendframework/zend-code/src/Scanner/TokenArrayScanner.php on line 582

when you have a php config file with ::class syntax:

<?php

return [
    'xxxx' => [
        'zzzz' => [
            'source_class' => \Test\Bla::class
        ]
    ]
];

Originally posted by @aight8 at zendframework/zend-code#67

Psalm integration

Feature Request

Q A
QA yes

Summary

As decided during the Technical-Steering-Committee Meeting on August 3rd, 2020, Laminas wants to implement vimeo/psalm in all packages.

Implementing psalm is quite easy.

Required

  • Create a psalm.xml in the project root
  • Copy and paste the contents from this psalm.xml.dist
  • Run $ composer require --dev vimeo/psalm
  • Run $ vendor/bin/psalm --set-baseline=psalm-baseline.xml
  • Add a composer script static-analysis with the command psalm --shepherd --stats
  • Add a new line to script: in .travis.yml: - if [[ $TEST_COVERAGE == 'true' ]]; then composer static-analysis ; fi
  • Remove phpstan from the project (phpstan.neon.dist, .travis.yml entry, composer.json require-dev and scripts)
Optional
  • Fix as many psalm errors as possible.

Check that two MethodGenerator instances hold metadata for methods with the same signature

Suppose I have two MethodGenerator instances - $methodA and $methodB.
Does this library provide a way to check, whether methods, that might be generated by $methodA and $methodB will have the same signature?
By the same signature I mean identical method names, same params with same type hints and same return types.
I thought there might be method like MethodGenerator::hasSameSignature(MethodGenerator $method) but I don't see anything like that in the class API.

I think it would be a very helpful feature, since for decorating class methods it's necessary to check that generated method has the same signature as existing one.


Originally posted by @petr-buchin at zendframework/zend-code#108

Use Reflection\FileReflection without including file?

From zendframework/zendframework#6860 which was just closed:

It looks like FileReflection uses token_get_all(file_get_contents($file)) to actually scan the file, so I am a little lost by the requirement of includeing it.

I am trying to fix some PHP classes programmatically, all of which have the same class name in the global namespace. To do this I was planning to reflect the files, get the class reflection, and instantiate the class generator from that to make my changes. Of course, since reflecting the file requires including it, I cannot do this right now, as it would have to re-declare the classes.

/cc @sasezaki @adamlundrigan who had activity on previous issue


Originally posted by @RSully at zendframework/zend-code#71

Internal class with parameters union type fail (php8)

Bug Report

Q A
Version(s) 3.5.0

Summary

Internal class with parameters union type fail (php8)

Current behavior

Exception with union type parameter

PHP Fatal error:  Uncaught Laminas\Code\Generator\Exception\InvalidArgumentException: Provided type "array|string|null" is invalid: must conform "/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*(\\[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)*$/" in /var/www/src/Generator/TypeGenerator.php:74
Stack trace:
#0 /var/www/src/Generator/ParameterGenerator.php(185): Laminas\Code\Generator\TypeGenerator::fromTypeString('array|string|nu...')
#1 /var/www/src/Generator/ParameterGenerator.php(67): Laminas\Code\Generator\ParameterGenerator->setType('array|string|nu...')
#2 /var/www/test.php(8): Laminas\Code\Generator\ParameterGenerator::fromReflection(Object(Laminas\Code\Reflection\ParameterReflection))
#3 {main}
  thrown in /var/www/src/Generator/TypeGenerator.php on line 74

How to reproduce

<?php

use Laminas\Code\Generator\ParameterGenerator;
use Laminas\Code\Reflection\ParameterReflection;

require 'vendor/autoload.php';

$parameter = ParameterGenerator::fromReflection(new ParameterReflection([\Phar::class, 'extractTo'], 1));

Expected behavior

Method body extract error with express static::class

Bug Report

Q A
Version(s) 3.4.1

Summary

class Foo
{
    public static function test() {
        return static::class;
    }
}

$class = \Laminas\Code\Generator\ClassGenerator::fromReflection(
    new \Laminas\Code\Reflection\ClassReflection(Foo::class));
echo $class->generate();

The test method body was not extract successfully.

Current behavior

Output code is :

class Foo
{

    public static function test()
    {
        return
    }


}

How to reproduce

Expected behavior

class Foo
{

    public static function test()
    {
        return static:class;
    }


}

PHP 8.0 support

Feature Request

Q A
New Feature yes

Summary

To be prepared for the december release of PHP 8.0, this repository has some additional TODOs to be tested against the new major version.

In order to make this repository compatible, one has to follow these steps:

  • Modify composer.json to provide support for PHP 8.0 by adding the constraint ~8.0.0
  • Modify composer.json to drop support for PHP less than 7.3
  • Modify composer.json to implement phpunit 9.3 which supports PHP 7.3+
  • Modify .travis.yml to ignore platform requirements when installing composer dependencies (simply add --ignore-platform-reqs to COMPOSER_ARGS env variable)
  • Modify .travis.yml to add PHP 8.0 to the matrix (NOTE: Do not allow failures as PHP 8.0 has a feature freeze since 2020-08-04!)
  • Modify source code in case there are incompatibilities with PHP 8.0

Return type self is not an internal type while code generation

Is it right behavior that TypeGenerator does not think self type is an internal type?
Because of that my code generation causes wrong return type in resulting file.
public function foo(): self
turns on
public function foo(): \self
It thinks self is a class.
Zend\Code\Generator\TypeGenerator:36
private static $internalPhpTypes = ['void', 'int', 'float', 'string', 'bool', 'array', 'callable', 'iterable'];


Originally posted by @mastiuhin-olexandr at zendframework/zend-code#161

MethodReflection::getPrototype() crashes when method has no return

When I use this method to grab the protype of a method of my class, it crashes with this error:

"Call to a member function getTypes() on boolean"

It happens because I have a method without return. My opinion is: the return type should be "void" on prototype. Issue #84 adresses the support for void. I've modified the code to make it return void. I could create a pull request if you guys want me to do so.

It was like this:

             $return = $docBlock->getTag('return');
             $returnTypes = $return->getTypes();
             $returnType = count($returnTypes) > 1 ? implode('|', $returnTypes) : $returnTypes[0];

And I've changed to this:

            $return = $docBlock->getTag('return');

            if($return === false)
            {
                $returnType = 'void';
            }
            else
            {
                $returnTypes = $return->getTypes();
                $returnType = count($returnTypes) > 1 ? implode('|', $returnTypes) : $returnTypes[0];
            }

If you don't think it should be void, at least set $returnType variable to empty string or null.
I've read the CONTRIBUTING.md, but I'm still pretty new to contributing on github, so fell free to get this code and push it into repository.

Regards


Originally posted by @ericklima-comp at zendframework/zend-code#154

Additional blank lines make generated class not PSR2 compliant

Hi guys

I saw PSR2 issues when generating classes.

See errors below

92 | ERROR | [x] Expected 1 blank line at end of file; 2 found
92 | ERROR | [x] The closing brace for the class must go on the next line after the body

I post you an exemple which generate these errors

<?php

namespace AppBundle\Domain\Entity;

class MyClass
{
    /**
     * @var int|null
     */
    private $id = null;

    /**
     * @param int $id
     * @return $this
     */
    public function setId($id)
    {
        $id = (int) $id;
        $this->id = $id;

        return $this;
    }

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }


}



Originally posted by @JuJuDropThor at zendframework/zend-code#135

Added some tests for #6499

This issue has been moved from the zendframework repository as part of the bug migration program as outlined here - http://framework.zend.com/blog/2016-04-11-issue-closures.html


Original Issue: https://api.github.com/repos/zendframework/zendframework/issues/6503
User: @rahuldroy
Created On: 2014-07-31T14:24:38Z
Updated At: 2015-05-07T13:37:25Z
Body


Comment

User: @Ocramius
Created On: 2014-07-31T15:11:25Z
Updated At: 2014-07-31T15:11:25Z
Body
Linking #6499


Comment

User: @weierophinney
Created On: 2014-08-07T16:42:14Z
Updated At: 2014-08-07T16:42:14Z
Body
@Ocramius is this an issue specific to our annotation support, or is it an issue in the Doctrine annotation library?


Comment

User: @Ocramius
Created On: 2014-08-07T16:49:09Z
Updated At: 2014-08-07T16:49:09Z
Body
Still not clear. I personally think Zend\Code may be passing a different string to the annotation parser.


Comment

User: @weierophinney
Created On: 2014-08-07T17:04:10Z
Updated At: 2014-08-07T17:04:10Z
Body
Removed milestone, as we cannot reliably reproduce.

In discussion with @Ocramius, it's possible that Zend\Code is passing an invalid string to the annotation parser. In looking at Zend\Code\Reflection\ClassReflection, however, the method we call is getAnnotations(), which passes the results of getDocComment() -- which is inherited directly from ReflectionClass. As such... this is very difficult to track.


Comment

User: @nickurt
Created On: 2014-08-08T08:45:05Z
Updated At: 2014-08-08T08:45:05Z
Body
@weierophinney @Ocramius Thanks for the reply's, I debugged some things.

The file Zend\Code\Scanner\AnnotationScanner -> __construct returns the correct docComment, but it fails in the tokenize function (#ref).

The currentChar (#ref) is here ...

string(1) "/"
string(1) "
"
string(1) " "
string(1) "
"
string(1) " "
string(1) "
"
string(1) " "
string(1) "
"
string(1) " "
string(1) "
"
string(1) " "
string(1) "
"
string(1) " "

Comment

User: @Ocramius
Created On: 2014-11-19T22:24:09Z
Updated At: 2014-11-19T22:24:09Z
Body
I see that this has indeed nothing to do with doctrine/annotations. Removing myself from the assignees as I cannot help with this issue right now.


Comment

User: @Maks3w
Created On: 2015-05-07T13:37:25Z
Updated At: 2015-05-07T13:37:25Z
Body
Do zendframework/zendframework#7113 fix this?



Originally posted by @GeeH at zendframework/zend-code#79

Not using return value of array_map in ClassGenerator->setImplementedInterfaces

https://github.com/zendframework/zend-code/blob/master/src/Generator/ClassGenerator.php#L476-L482 has the following snippet

        array_map(function ($implementedInterface) {
            return (string) TypeGenerator::fromTypeString($implementedInterface);
        }, $implementedInterfaces);

        $this->implementedInterfaces = $implementedInterfaces;

That's a no-op, since the return value of the array_map isn't used. I think that the array_map should be removed, replaced with array_walk (probably pointless unless it would throw), or (probably) be changed to:

        $this->implementedInterfaces = array_map(function ($implementedInterface) {
            return (string) TypeGenerator::fromTypeString($implementedInterface);
        }, $implementedInterfaces);

The latter seems likely given the rest of the changes in zendframework/zend-code@ec09875

This was detected via static analysis, I'm not sure of the impact of fixing this.

http://php.net/array_map


Originally posted by @TysonAndre at zendframework/zend-code#165

PropertyGenerator::setDefaultValue incorrectly handles ValueGenerator instances

Related to #96, PropertyGenerator behaves incorrectly when the default value passed into it is a ValueGenerator instead of a PropertyValueGenerator.

Example (lifted from #96):

<?php
<<<CONFIG
packages:
    - "zendframework/zend-code: ^3.0"
CONFIG;

$classGenerator    = new \Zend\Code\Generator\ClassGenerator();
$propertyGenerator = new \Zend\Code\Generator\PropertyGenerator();
$value             = new \Zend\Code\Generator\ValueGenerator();
$value->setValue('DefaultString');
$value->setType(\Zend\Code\Generator\ValueGenerator::TYPE_STRING);
$propertyGenerator->setName("foo");
$propertyGenerator->setDefaultValue($value->generate());

$classGenerator->addPropertyFromGenerator($propertyGenerator);

print $classGenerator->generate();

Will print this:

class 
{

    public $foo = '\'DefaultString\'';


}

PropertyGenerator::setDefaultValue wraps everything that isn't a PropertyValueGenerator instance in a new instance of that class. IMO setDefaultValue should not accept ValueGenerator instances or at least convert to a PropertyValueGenerator, vs composing one into the other as is presently the case. This change does break BC, however.


Originally posted by @adamlundrigan at zendframework/zend-code#97

Adding parameters of type that exists in "use" statements

Unless I'm missing something, there is no way to add a type-hinted parameter to a method that does not use the fully-qualified name (as it exists as a use statement).

e.g. (See SomeClass type-hint in method)

use Foo\Bar\SomeClass;

class GeneratedClass
{
    public function generatedMethod(SomeClass $instance) {
    }
}

If you don't supply a fully-qualified name, it looks like:

use Foo\Bar\SomeClass;

class GeneratedClass
{
    public function generatedMethod(\SomeClass $instance) {
    }
}

Originally posted by @postalservice14 at zendframework/zend-code#37

addConstant() is producing code with keyword `public`

addConstant() method is outputting with invalid output:

public const ELEMENT_PROPERTY1 = 'property1';

(notice the public keyword)

DETAILS:
PropertyGenerator.php line: 232, we need to drop $this->getVisibility()

Update AnnotationScanner.php

This issue has been moved from the zendframework repository as part of the bug migration program as outlined here - http://framework.zend.com/blog/2016-04-11-issue-closures.html


Original Issue: https://api.github.com/repos/zendframework/zendframework/issues/7113
User: @nouc23
Created On: 2015-01-09T10:38:17Z
Updated At: 2015-05-07T14:11:59Z
Body
I know we should write code using PSR standard but life is different.
While we use tabs script ignore annotations.

Fixes #5595


Comment

User: @Ocramius
Created On: 2015-01-09T10:38:57Z
Updated At: 2015-01-09T10:38:57Z
Body
This requires a test asset containing tabs, and a related test


Comment

User: @nouc23
Created On: 2015-01-09T10:58:53Z
Updated At: 2015-01-09T10:58:53Z
Body
done


Comment

User: @weierophinney
Created On: 2015-02-19T20:50:49Z
Updated At: 2015-02-19T20:50:49Z
Body
Needs:

  • Rebase
  • new test.

Comment

User: @Maks3w
Created On: 2015-05-07T13:57:11Z
Updated At: 2015-05-07T13:57:11Z
Body
I've pulled this and found the test is not related with the change made in scanner. So I don't know what is trying to fix this. Test never fails.


Comment

User: @nouc23
Created On: 2015-05-07T14:11:59Z
Updated At: 2015-05-07T14:11:59Z
Body

I edit existing test, and I was told to create new one.

I forgot to do that and also I doesnt use github much. I try to finish this up on days.

Wysłano z aplikacji myMail dla Androida
czwartek, 07 maja 2015, 03:57PM +02:00 od Maks3w [email protected]:

I've pulled this and found the test is not related with the change made in scanner. So I don't know what is trying to fix this. Test never fails.

Reply to this email directly or  view it on GitHub .



Originally posted by @GeeH at zendframework/zend-code#78

TypeGenerator regex pattern does not validate union return types

When using class methods with PHP 8 union return types, an InvalidArgumentException is triggered.

Example processing the (simplified) method

    public function getSomeValue(int $id): array|bool
    {
        return $this->orm->fetchValue($id); // Can return either the database result as an array or FALSE if no results are found.
    }

leads to the following error:

Details
Type: Laminas\Code\Generator\Exception\InvalidArgumentException
Code: 0
Message: Provided type "array|bool" is invalid: must conform "/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*(\\[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)*$/"
File: D:\...\vendor\laminas\laminas-code\src\Generator\TypeGenerator.php
Line: 74

Some constants are not rendered properly

RFC

Q A
Proposed Version(s) 4
BC Break? No

Goal

Hi,

I might be wrong, but here it is, I implemented a new test which is failing.

    public function testPropertyDefaultValueCanHandleBool()
    {
         $valueGenerator1 = new ValueGenerator(
            'FALSE',
            ValueGenerator::TYPE_AUTO,
            ValueGenerator::OUTPUT_MULTIPLE_LINE
        );

        $valueGenerator2 = new ValueGenerator(
            'FALSE',
            ValueGenerator::TYPE_STRING,
            ValueGenerator::OUTPUT_MULTIPLE_LINE
        );

        $valueGenerator1->initEnvironmentConstants();
        $valueGenerator2->initEnvironmentConstants();

        self::assertNotEquals($valueGenerator1->generate(), $valueGenerator2->generate());
    }

Basically, FALSE is a defined constant: https://3v4l.org/8Rpd1

When I run this test, I get:

There was 1 error:

1) LaminasTest\Code\Generator\ValueGeneratorTest::testPropertyDefaultValueCanHandleBool
strpos(): Empty needle

/home/pol/dev/git/laminas-code/src/Generator/ValueGenerator.php:314
/home/pol/dev/git/laminas-code/src/Generator/ValueGenerator.php:350
/home/pol/dev/git/laminas-code/test/Generator/ValueGeneratorTest.php:393

I will submit a PR fixing this issue.

Fix return type of FileGenerator::getClass

Provide a narrative description of what you are trying to accomplish:

  • [Y ] Is this related to quality assurance?
    Return type of \Zend\Code\Generator\FileGenerator::getClass only has ClassGenerator while it can also return false when the classes array is empty.
    PHPStan will whine about this, because it should always return a true-thy return, also it gives the perception it will always return the ClassGenerator (while it doesn't always do that)

Therefor I added the false to the return type in the docblock.


Originally posted by @janvernieuwe at zendframework/zend-code#177

E_NOTICE with trait method aliases

I'm getting Notice: Undefined offset: 1 in /path/to/vendor/zendframework/zend-code/src/Scanner/ClassScanner.php on line 596 using 3.1.0. It looks like this happens with aliased trait methods:

trait A 
{
    function a() {
        // does something
    }
}

class B 
{
    use A {
        a as b;
    }

    function a() {
        b();
        // do something more
    }
}

Stepping through the code it looks like $alias['original'] does not contain '::', causing the notice. I ran into this using zend-expressive-tooling on an existing project. It doesn't seem to cause anything other than annoyance, but I'm not sure if just adding a check for '::' would hide a deeper problem. Thoughts?


Originally posted by @kynx at zendframework/zend-code#104

Allow generators instead of deriving from strings in various Generator classes

Referencing #30 and the issue with type-hinted parameters.

Currently the method for setting Type Hints in the ParameterGenerator enforces an object by deriving the TypeGenerator from a string.

     * @param  string $type
     * @return ParameterGenerator
     */
    public function setType($type)
    {
        $this->type = TypeGenerator::fromTypeString($type);

        return $this;
    }

It would be trivial and would not break existing code to change the method to allow a $type of either a string or a GeneratorInterface to be passed in, and therefore allow custom treatment of type hints (allowing aliases)

     * @param  string $type
     * @return ParameterGenerator
     */
    public function setType($type)
    {
        if (! ($type instanceof GeneratorInterface)) {
            $type = TypeGenerator::fromTypeString($type);
        }
        $this->type = $type;

        return $this;
    }

Would really appreciate this minor change being implemented - it creates as much work to re-code generated code to be less verbose when it could be easily avoided.

[RFC]: Next major version of package. Stricter types for methods, API cleaning.

RFC

Q A
Proposed Version(s) 5.x.x
BC Break? Yes

Goal

I want to discuss next major version of this package and what can be improved in it to have better API for this package.

Background

Current version of package contains too many places where method of a class can accept different types at the same time: string/arrays/specific objects. This makes code error-prone and harder to debug, harder to use and increases chances of errors as IDE doesn't help too much when all checks are in runtime. Also static analysis tools complain about types for this library.

Proposal(s)

  1. To add declare(strict_types=1) to all source files to benefit more from stronger type checks
  2. To to add type information to all method signatures (parameter and return types), which will be obviously a BC break, but it will improve code quality a lot.
  3. As 2) will bring a BC break, I want to propose to drop all public static function fromArray(array $array) static constructors from the code, as all these constructors accept non-typed arrays, thus IDE doesn't know about possible keys and can't verify types with static analysis tools. Same should be applied to the AbstractGenerator::setOptions($options) - IMO, it should be removed for the next major version.
  4. Drop all optional arguments from constructors, making ctor signatures smaller and cleaner, eg instead of
    ParameterGenerator::__construct(
        $name = null,
        $type = null,
        $defaultValue = null,
        $position = null,
        $passByReference = false
    );

new signature will be

    ParameterGenerator::__construct(string $name);

As we already have mutation methods in the API, we can use fluent interfaces to adjust generated code item by making required changes:

$parameterGenerator = new ParameterGenerator('test');
$parameterGenerator
    ->setType(TypeGenerator::fromTypeString('string'))
    ->setDefaultValue('foo')
    ->setPassByReference(true);

This should make interface for configuration more stable, as there will be only one way to configure generator via setters that can mutate instance (no more fromArray, no more tons of args in ctors).

  1. Drop all mixed types for method signatures, eg:
    /**
     * Set the default value of the parameter.
     *
     * Certain variables are difficult to express
     *
     * @param  null|bool|string|int|float|array|ValueGenerator $defaultValue
     * @return ParameterGenerator
     */
    public function setDefaultValue($defaultValue);

will be replaced with following signature:

    /**
     * Set the default value of the parameter.
     */
    public function setDefaultValue(ValueGenerator $defaultValue): ParameterGenerator

There are much more examples, eg ClassGenerator::addMethods() that accepts one of 3 possible types of argument.

  1. Close API from inheritance - this library should provide building blocks for code generation, if all main functionality will be covered in the library, then we can close all general classes with final keyword, allowing only composition of code from building blocks.

Considerations

API will change a lot, so definitely we will have a BC break. However, all changes can be reproduced via setters and new API, so migration from current version of code to the new one is just matter of wrapping existing code in external libraries with additional setters and type wrappers.

Appendix

Many syntax errors with v4.0.0 after using `vimeo/psalm` on php7.4

v4.0.0 creates those enigmatic bugs on php7.4 after run vendor/bin/psalm --show-info=false:
I tested it on psalm 4.1, 4.2 and 4.3. Every cases are the same:

Error: Syntax error, unexpected T_STRING, expecting T_PAAMAYIM_NEKUDOTAYIM on line 480
Error: Syntax error, unexpected T_VARIABLE, expecting ')' on line 480
Error: Syntax error, unexpected ')' on line 481
Error: Syntax error, unexpected T_STRING, expecting T_PAAMAYIM_NEKUDOTAYIM on line 495
Error: Syntax error, unexpected T_VARIABLE, expecting ')' on line 495
Error: Syntax error, unexpected ')' on line 496
Error: Syntax error, unexpected T_STRING, expecting T_PAAMAYIM_NEKUDOTAYIM on line 59
Error: Syntax error, unexpected T_VARIABLE, expecting ')' on line 59
Error: Syntax error, unexpected ',' on line 59
Error: Syntax error, unexpected ')' on line 63
Error: Syntax error, unexpected T_STRING, expecting T_PAAMAYIM_NEKUDOTAYIM on line 105
Error: Syntax error, unexpected T_VARIABLE, expecting ')' on line 105
Error: Syntax error, unexpected ')' on line 107
Error: Syntax error, unexpected T_VARIABLE, expecting ')' on line 161
Error: Syntax error, unexpected ',' on line 161
Error: Syntax error, unexpected ')' on line 163
Error: Syntax error, unexpected T_VARIABLE, expecting ')' on line 185
Error: Syntax error, unexpected ',' on line 185
Error: Syntax error, unexpected ')' on line 187
Error: Syntax error, unexpected T_STRING, expecting T_PAAMAYIM_NEKUDOTAYIM on line 161
Error: Syntax error, unexpected T_VARIABLE, expecting ')' on line 161
Error: Syntax error, unexpected ')' on line 161
Error: Process completed with exit code 1.

It occured in Sylius:
Screenshot 2020-12-30 at 20 27 52

"newLine" Bug in MethodGenerator class

The static function {{Zend\Code\Generator\MethodGenerator::clearBodyIndention}} fails on Windows 10, php 7.1. in line 83: $lines = explode(PHP_EOL, $body);
$body does not contain any PHP_EOL (\n\r) characters, no matter what line ending encoding the source content had before.
works well on Linux, OSX.

quick fix:
change line 83 to
$lines = explode("\n", $body);


Originally posted by @finalJustize at zendframework/zend-code#111

Compile error type on MethodGenerator.php line 25 using php 8.0

Using php 8.0 with symfony in my case, I could see the following bug while container is building:

"laminas/laminas-code": "4.2.1"

Type of Laminas\Code\Generator\MethodGenerator::$docBlock must be ?Laminas\Code\Generator\DocBlockGenerator (as in class Laminas\Code\Generator\AbstractMemberGenerator) in /app/vendor/laminas/laminas-code/src/Generator/MethodGenerator.php on line 25

It seems that the property protected ?DocBlockGenerator $docBlock = null due an error type.

I've tried to remove type hint DocBlockGenerator to do a test and it works.

Your package is automatically added when syfony/orm-pack is installed, but this bug makes an error and don't allow to use it.

This package should not "replace" zend/code

Bug Report

Q A
Version(s) 3.4.1

Summary

This package is marked as replacing zendframework/zend-code:

"replace": {
"zendframework/zend-code": "self.version"
}

There seems to be a misunderstanding in what replace actually does: the package must be 100% compatible with the replaced one, which is obviously not the case here.

As it stands, this breaks composer installations and throws class not found errors.

Sure, you can install the laminas/laminas-zendframework-bridge, but composer doesn't do that automatically.

Current behavior

Class 'Zend\Code\Generator\ClassGenerator' not found

How to reproduce

Install ocramius/proxy-manager on PHP 7.3; try to use it.

[ZF3] FQCN in parameter type hints

This issue has been moved from the zendframework repository as part of the bug migration program as outlined here - http://framework.zend.com/blog/2016-04-11-issue-closures.html


Original Issue: https://api.github.com/repos/zendframework/zendframework/issues/4149
User: @Ocramius
Created On: 2013-03-30T11:59:09Z
Updated At: 2014-09-28T00:34:50Z
Body
This PR introduces FQCNs for type-hints in generated method signatures. This is a BC break, but it is necessary to use the code generator when the generated code is not placed on a dedicated file.

Before:

public function doFoo(Foo $foo) {}

After

public function doFoo(\Foo $foo) {}

This PR also takes into account the new PHP 5.4 callable data type when generating code.


Comment

User: @Ocramius
Created On: 2013-04-08T14:28:13Z
Updated At: 2013-04-08T14:28:13Z
Body
@prolic ping? You used Zend\Code quite a bit - is this a huge BC break for you?


Comment

User: @prolic
Created On: 2013-04-08T23:02:49Z
Updated At: 2013-04-08T23:02:49Z
Body
I am okay with these changes. This helps in more situations as I would expect troubles with it.


Comment

User: @weierophinney
Created On: 2013-04-12T16:36:04Z
Updated At: 2013-04-12T16:36:04Z
Body
Would it be possible to make this optional via a flag?

I ask, because our own CS indicates that parameter type hints should not be fully qualified; they should always resolve to current imports. The use case you're specifying here is highly specific -- it's for when classes are not in dedicated files, which, again, was not the original purpose, and goes against our own CS and recommendations.

That said, I can see the rationale for having this, but doing it as an optional behavior makes more sense to me.


Comment

User: @Ocramius
Created On: 2013-04-12T16:38:03Z
Updated At: 2013-04-12T16:38:03Z
Body
I'll think of a way of making this optional. The fact is that this currently makes it impossible to have classes generated via generate() without a filegenerator too (for eval'd code)


Comment

User: @icywolfy
Created On: 2013-04-16T16:57:20Z
Updated At: 2013-04-16T16:57:20Z
Body
Why would one need to use FQCN when multiple classes are in the same file/eval'd code?
So long as each section is prefixed with a non-global namespace; there's no issue with conflicting uses/namespaces.
And if you need to use the global namespace, then bracketed notation is better.

so

namespace Foo;
class A {}

namespace Foo;
use Foo\A as Bar;
class C extends Bar {}

namespace Foo;
interface B {}

namespace Foo\Bar\Baz;
use Foo\A as Baz;
use Foo\B as Bar;

class C extends Baz implements Bar {}

or if you need global support: (this isn't supported in the ClassGenerator)

namespace Foo {
class A{}
}
namespace {
use Foo\A as Bar;
class B extends Bar {}
}
namespace Foo {
use B as Bar;
class B extends Bar {}
}

But, I would personally see the above generated/used rather than giving users the option of using FQCN, since it's still much better to be using Use statements if only to promote better coding habits.

But that said, I have had no issues generating multiple classes into a single cached-file, or dynamic unclusion via eval() at work (hate using eval, but since the temporary classes don't live in the filesystem, can't really auto-load it)


Comment

User: @Ocramius
Created On: 2013-04-16T21:26:17Z
Updated At: 2013-04-16T21:26:17Z
Body
@icywolfy this causes a number of problems atm.

Just as a simple example, take multiple imported classes with the same name.

Using the FQCN is not better from a CS perspective, but honestly, nobody should ever care about generated code CS.


Comment

User: @icywolfy
Created On: 2013-04-16T23:05:33Z
Updated At: 2013-04-16T23:05:33Z
Body
@Ocramius Perhaps, but just don't see the issues with

    $x = new ClassGenerator('A');
    $x->setNamespaceName('Foo\Bot');
    $x->addUse('Foo\Bar\A', 'BarA');
    $x->addUse('Foo\Baz\A', 'BarB');
    $x->addUse('FooBar');
    $x->addMethod('doSomething', array(
      new ParameterGenerator('barA', 'BarA'),
      new ParameterGenerator('bazA', 'BazA'),
      new ParameterGenerator('botA', 'A'),
      new ParameterGenerator('subBotA', 'Sub\A'),
    ));
    $x->addMethod('somethingElse', array(
      new ParameterGenerator('barA', 'BarA'),
      new ParameterGenerator('api', 'FooBar\Service\ApiInterface $api'),
   ));

Or if you need to use a FQCN, explicitly prepend add the '' during generation;
(we just "use" our global and vendor prefixes namespaces)

Though I would love to have it propagate use-aliases set against methods; so that you can define the aliases you use in the method-body and have it resolve up to the class-level and be added to the generator (and throw exception if conflicting use-aliases are used)

But, we here heavily use the generated code for both sub-project generation, and for use of user and type management; User's are generated upon major changes, types are rebuilt/committed to code-base based on the config files.

We do manual changes for people to meet their desired behaviours and mark their classes as manually edited, and then treat them specially until such time that it's properly incorporated into the build/generation process. But since we are actually using\editing the generated code, it's nice to have it be readily readable.
Though fundamentally I'm against BC breaks now that ZF2 is relatively stable in the 2.1.x branch.

# <user>.php :
namespace <type>\<user>;
use <type>\User as BaseUser;

class User extends BaseUser {
   private $manualEdit = false;
   function getRole() { ...  return new Role\BaseRole()  }
   function hasRole($roleName) { return class_exists(Role\<$roleName>); }
...
}

namespace <type>\<user>\Role;
use <type>\<user> as BaseUser;
use <type>\TypeInterface;
class BaseRole implements TypeInterface { ... }

namespace <type>\<user>\Contact;
use ...
class Address extends Address\<country> { ... }

(we are operating without access to a database for several of the East-coast data-centres, and this was the solution that was ended up on, it's actually quite nice, if not a bit unconventional. Damned lawyers dictating how things work.)


Comment

User: @Ocramius
Created On: 2013-04-17T07:42:23Z
Updated At: 2013-04-17T07:42:23Z
Body
That's way too complex for no real reason. Having FQCN simply removes all these problems at once. I'll see about the break - for now I had to subclass ALL generators to get rid of the problem, since the current API is unusable.


Comment

User: @ralphschindler
Created On: 2013-06-06T22:48:45Z
Updated At: 2013-06-06T22:48:45Z
Body
@Ocramius after a cursory review, I'm ok with this, do you still feel like this should be merged?


Comment

User: @Ocramius
Created On: 2013-06-06T23:13:21Z
Updated At: 2013-06-06T23:13:46Z
Body
@ralphschindler not sure since it's a bc break. Gimme some more time, otherwise feel free to close this and I'll redo it somehow.


Comment

User: @EvanDotPro
Created On: 2013-10-15T03:05:44Z
Updated At: 2013-10-15T03:05:44Z
Body
@Ocramius ping? Let's either get this merged or refactored. 😄


Comment

User: @Ocramius
Created On: 2014-02-04T12:05:50Z
Updated At: 2014-02-04T12:05:50Z
Body
This cannot land in 2.x - I'll keep my adaptation in my library and the issue open since it's a quite relevant "bug"


Comment

User: @weierophinney
Created On: 2014-03-03T16:31:55Z
Updated At: 2014-03-03T16:31:55Z
Body
Marking for 3.0.0



Originally posted by @GeeH at zendframework/zend-code#76

There is no @return existence check when prototyping

Insufficient return value validation

Class \Laminas\Code\Reflection\MethodReflection
Method: getPrototype
Line: 100

if ($docBlock) {
            $return = $docBlock->getTag('return');
            $returnTypes = $return->getTypes();   // return false
            $returnType = count($returnTypes) > 1 ? implode('|', $returnTypes) : $returnTypes[0];
}

There is no check for the existence of @return. If it is absent, we get an exception "Call to a member function getTypes() on bool"

Notice when using array as default value for parameter

I'm trying to set array for default value:

public function exportCategory($sourceId, $targetParentId, $params = [1, 2, 3])

And getting notice:

Notice: Undefined index: type in /home/forever/prj/Enterum/vendor/zendframework/zend-code/src/Scanner/MethodScanner.php on line 322

25  0.2380  7434808 KJSencha\Direct\Remoting\Api\Factory\ApiBuilder->buildAction( ) .../ApiBuilder.php:138
26  0.2551  7955224 KJSencha\Direct\Remoting\Api\Factory\ApiBuilder->buildMethod( ) .../ApiBuilder.php:162
27  0.2551  7955352 Zend\Code\Scanner\MethodScanner->getNumberOfParameters( )   .../ApiBuilder.php:178
28  0.2551  7955352 Zend\Code\Scanner\MethodScanner->getParameters( )   .../MethodScanner.php:308

Below is a piece of ApiBuilder.php:

/**
 * Builds and populates Action object based on the provided class name
 *
 * @param  string $className
 * @return Action
 */
public function buildAction($className)
{
    $classReflection = new ClassReflection($className);
    $scanner = new FileScanner($classReflection->getFileName(), $this->annotationManager);
    $classScanner = $scanner->getClass($classReflection->getName());
    $action = new Action($classScanner->getName());

    foreach ($classScanner->getMethods() as $classMethod) {
        if ($classMethod->isPublic() && $classMethod->getName() != '__construct') {
            $action->addMethod($this->buildMethod($classMethod));
        }
    }

    return $action;
}

/**
 * Builds a method object based on the provided method scanner
 *
 * @param  MethodScanner $classMethod
 * @return Method
 */
protected function buildMethod(MethodScanner $classMethod)
{
    $method = new Method($classMethod->getName());
    $method->setNumberOfParameters($classMethod->getNumberOfParameters());

    // Loop through annotations
    if ($annotations = $classMethod->getAnnotations($this->annotationManager)) {
        foreach ($annotations as $annotation) {
            // @todo annotations should implement some kind of interface?
            if (method_exists($annotation, 'decorateObject')) {
                $annotation->decorateObject($method);
            }
        }
    }

    return $method;
}

With $params = [1,2], for example, notice disapears.


Originally posted by @4orever at zendframework/zend-code#88

Zend\Code\Scanner\MethodScanner does not account for scalar type declarations

I believe the issue is with MethodScanner and not ParameterScanner, as this is what is actually parsing the PHP tokens - it correctly ignores non-scalar type declarations such as array and callable. From what I can tell, string, int, bool and float are tokens of type T_STRING. As a result, the scanner believes they are classnames. This can result in classnames that simply don't exist.

I'm not really sure how this can be worked around inside the scanner. As far as I can tell, no PHP version checks are performed on the code being parsed, which means there's no reliable way of detecting whether or not string is an actual classname in PHP <7.0 code, or a scalar type declaration in PHP >=7.0 code.

Perhaps there needs to be some way to globally set the PHP version of the code being scanned?


Originally posted by @djmattyg007 at zendframework/zend-code#56

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.