Page 1 of 2

PHP use and namespaces

PostPosted: Tue 3 Oct 2017 14:05
by fbernoldi
Hi,

In PHP you can do something like:

Code: Select all
<?php

namespace Test;

use \SomeNamespace\SomeClass;
use \SomeVeryLargeAnoyingNamespace\SomeVeryLargeAnoyingClass as SVLAC;

class Test {

    public function dependency() {
        $s = new SomeClass;
        $svlac = new SVLAC;
        $svlac2 = new \SomeVeryLargeAnoyingNamespace\SomeVeryLargeAnoyingClass();
    }

    public function someNiceMethod(SVLAC $hello) {
        // something php 7 friendly
    }

    /**
     * @param SVLAC $hello some hi hi.  (@param ${t0} ${p0} ...)
     */
    public function someNiceMethodUntyped($hello) {
        // something php 5 friendly
    }

    /**
     * @param SVLAC $hello some hi hi. (@param ${t0} ${p0} ...)
     * @return SVLAC (${type})
     */
    public function someNiceMethodReturning(SVLAC $hello) : SVLAC {
        // something php 7.1 friendly
        return $hello;
    }

    /**
     * @param \SomeVeryLargeAnoyingNamespace\SomeVeryLargeAnoyingClass $hello Some hello thing
     */
    public function someUglyMethod(\SomeVeryLargeAnoyingNamespace\SomeVeryLargeAnoyingClass $hello) {
        // something else
    }

}


Currently there is a force namespace prefix but I can't find a way to use it this way, it's quite demanding to add the uses you need to artifacts manually.

So the feature request would be that the current "import" dependency generates a PHP use statement at least so you can use the alias "SomeClass" instead of "\SomeNamespace\SomeClass", I don't know how to solve the "SVLAC" alias case.

And for the methods like "someNiceMethod" to generate a PHP use statement automatically and use it when the force namespace prefix is not set (for example).

These features would be very useful for big projects with a lot of namespaces!

Thanks,
Federico.

Re: PHP use and namespaces

PostPosted: Thu 5 Oct 2017 16:05
by Bruno Pagès
Hello,

About force namespace prefix, supposing the class A and B are in same package P and A extends B :
  • if force namespace prefix is not set the generated code is class A extends B ...
  • if force namespace prefix is set the generated code is class A extends \P\B ...

Yes, currently the uses have to be added to artifacts manually.

The dependencies are already used to generate code, they allow to generate additional require_once whatever their stereotypes. Let's note the require_once are automatically generated, for instance if A has an attribute of type B and A generated in A.php and B generated in B.php, the code generated in A.php will contain require_once 'B.php'; even it is not explicitly required through a dependency

I can modify the dependency management between two classes, for instance for a dependency A - - -> B :
  • if the stereotype is use the generated code in A.php will be a use B; (if necessary with the namespace where B is)
  • if the stereotype is use-as FOO the generated code will be a use B as FOO; (if necessary with the namespace where B is)

So the feature request would be that the current "import" dependency generates a PHP use statement ...

And for the methods like "someNiceMethod" to generate a PHP use statement automatically and use it when the force namespace prefix is not set (for example).


I don't understand, the same use form is generated in both cases, when there is a dependency for the first case, without dependency in the second case, what is the interest to have a dependency ?

Re: PHP use and namespaces

PostPosted: Mon 9 Oct 2017 19:40
by fbernoldi
Hi Bruno,

Bruno Pagès wrote:Hello,

About force namespace prefix, supposing the class A and B are in same package P and A extends B :
  • if force namespace prefix is not set the generated code is class A extends B ...
  • if force namespace prefix is set the generated code is class A extends \P\B ...

Yes, currently the uses have to be added to artifacts manually.

The dependencies are already used to generate code, they allow to generate additional require_once whatever their stereotypes. Let's note the require_once are automatically generated, for instance if A has an attribute of type B and A generated in A.php and B generated in B.php, the code generated in A.php will contain require_once 'B.php'; even it is not explicitly required through a dependency

I can modify the dependency management between two classes, for instance for a dependency A - - -> B :
  • if the stereotype is use the generated code in A.php will be a use B; (if necessary with the namespace where B is)
  • if the stereotype is use-as FOO the generated code will be a use B as FOO; (if necessary with the namespace where B is)

So the feature request would be that the current "import" dependency generates a PHP use statement ...


Great!

Bruno Pagès wrote:
And for the methods like "someNiceMethod" to generate a PHP use statement automatically and use it when the force namespace prefix is not set (for example).


I don't understand, the same use form is generated in both cases, when there is a dependency for the first case, without dependency in the second case, what is the interest to have a dependency ?


The goal is that BoUML generates the short class names according to the uses declared, for dependencies, associations and method signature.

i.e. for an association:

Code: Select all
<php

use SNamespace\SClass;

class HelloClass {

    /**
     * @var SClass this could be an association with stereotype "use" with return type SNamespace\SClass using ${type} in documentation.
     */
    private $asociated_instance;

}



For a method signature:

Code: Select all
<php

use SNamespace\SClass;

class HelloClass {

    /**
     * @param SClass $sclass some typed ${t0} param
     * @return SClass some return ${type}
     */
    public function hello (SClass $sclass) {
        // ...
        return $sclass;
    }

}



I hope I explained better with separated examples.

Regards,
Federico.

Re: PHP use and namespaces

PostPosted: Sat 21 Oct 2017 21:13
by Bruno Pagès
Hi Federico,

Bouml 7.1.3 is available and add use generation

Please refer to the historic for details

Regards,
Bruno

Re: PHP use and namespaces

PostPosted: Sun 22 Oct 2017 10:40
by fbernoldi
Hi Bruno,

Thank you very much! I'll look into it and give it a try :)

Regards,
Federico.

Re: PHP use and namespaces

PostPosted: Mon 23 Oct 2017 17:11
by fbernoldi
This is great! I've started using it for new classes and to replace existing uses on project model I have and I've found some issues:

1) When the use belongs to the same namespace route, bouml generates partial use path.

i.e for "Cat" belonging to "\Animals\Mammals" namespace, a realization dependency stereotyped as "use-as Feline" to "\Animals\Mammals\FelineInterface":

bouml generates:

Code: Select all
<?php

namespace \Animal\Mammals;

use FelineInterface as Feline;

class Cat implements Feline {
   // ---
}



For PHP this is not correct since it expects a full definition path, and the generated "Feline" use is referencing to "\FelineInterface" instead of "\Animals\Mammals\FelineInterface". Adding a full path to use statement corrects this.

should be:

Code: Select all
<?php

namespace \Animals\Mammals;

use \Animals\Mammals\FelineInterface as Feline;

class Cat implements Feline {
   // ---
}



This is the most important fix for me to use this feature everywhere.

2) When I was testing case one I've found that when you change the regular realization of FelineInterface to a stereotyped "use-as Feline" realization, php generator skips the require_once statement.

i.e generated regular FelineInterface realization:

Code: Select all
<?php

namespace \Animals\Mammals;

require_once 'animals/mammals/FelineInterface.php';

class Cat implements FelineInteface {
   // ---
}



generated stereotyped "use-as Feline" realization with the same artifact:

Code: Select all
<?php

namespace \Animals\Mammals;


use FelineInterface as Feline;

class Cat implements FelineInteface {
   // ---
}



I normally don't use require_once since I use autoloaders for classes, but maybe it's an issue for someone. Most actual php projects autoloaders instead of require statements.

For stereotyped "use" and "use-as" realizations the require_once is not created.
For stereotyped "use" and "use-as" dependencies the require_once is not created.
For stereotyped "use" and "use-as" associations the require_once is not created.
For stereotyped "use" and "use-as" generalizations the require_once is created correctly.

3) Roundtrip PHP:

- Works fine for "use" and "use-as" stereotypes for generalizations.
- Ignores "use" and "use-as" stereotypes for realizations and dependencies.
- I think that roundtrip is treating every association as an attribute, (maybe it needs to check if the attribute in the file is an association in the model?), also not working for "use" and "use-as" associations.

Roundtrip is a great feature, this errors in most cases have no impact or they are easy to fix since the feature does not automatically delete these changes, it's just un mark them and delete the created "unknown" new classes or i.e. the "duplicated" realizations.

4) Provide a way to add documentation to use dependency?

for example:

Code: Select all
<?php

namespace \Animals\Mammals;

// Feline interface to use on cats.
use \Animals\Mammals\FelineInterface as Feline;

class Cat implements Feline  {
   // ---
}



In bouml if we add a @{meow} and set the value to "// Feline interface to use on cats." and we add it to the PHP declaration as:

Code: Select all
@{meow}
${type}


it gets replaced as:

Code: Select all
<?php

namespace \Animals\Mammals;

use \Animals\Mammals\Feline;

class Cat implements // Feline interface to use on cats.
Feline  {
   // ---
}



This is not a priority, the same documentation could be written elsewhere by some other means.

Thanks for your time.

Regards,
Federico.

PS: I've edited and drafted this many times so I might write a little nonsense somewhere.

Re: PHP use and namespaces

PostPosted: Mon 23 Oct 2017 18:36
by Bruno Pagès
I am quite desperate :?

fbernoldi wrote:1) When the use belongs to the same namespace route, bouml generates partial use path.

I compute the path like for the other cases, the fact use doesn't allow that is a pity

While we are there, a partial path is legal when referencing a class for instance in an inheritance or I am always wrong ?

fbernoldi wrote:2) When I was testing case one I've found that when you change the regular realization of FelineInterface to a stereotyped "use-as Feline" realization, php generator skips the require_once statement.

...

For stereotyped "use" and "use-as" realizations the require_once is not created.
For stereotyped "use" and "use-as" dependencies the require_once is not created.
For stereotyped "use" and "use-as" associations the require_once is not created.
For stereotyped "use" and "use-as" generalizations the require_once is created correctly.

:shock: The stereotype use and use-as are only relevant for the dependencies, I never speak about them for the other relations

In case a required_once is generated out of a dependency, the fact you have a dependency stereotyped use or use-as AZE changes nothing, the required_once is still generated

If the require_once was generated by a dependency and you modify this dependency to set its stereotype to use or use-as AZE, of course the required_one is not any more generated. To have both of them you need two dependencies

fbernoldi wrote:3) Roundtrip PHP:

- Works fine for "use" and "use-as" stereotypes for generalizations.
- Ignores "use" and "use-as" stereotypes for realizations and dependencies.

As you can see in the historic of the 7.1.3 there is no new version for the reverse nor roundtrip. While the reverse/roundtrip do not create dependencies for use and use-as forms but put them in the textual definition of the artifacts it is normal and expected the roundtrip deletes them

Again the stereotypes use and use-as are only relevant for dependencies

fbernoldi wrote:4) Provide a way to add documentation to use dependency?

I did not remember that I was doing this for other kind of relations :roll:
It is strange I do not allow ${comment} or ${description} in place of the complicated alias way :?

Re: PHP use and namespaces

PostPosted: Tue 24 Oct 2017 10:50
by fbernoldi
I compute the path like for the other cases, the fact use doesn't allow that is a pity

I don't know why, the docs state that you have to use full class path when importing: http://php.net/manual/en/language.namespaces.importing.php

While we are there, a partial path is legal when referencing a class for instance in an inheritance or I am always wrong ?


You are not wrong here, this is correct and can be used.

The stereotype use and use-as are only relevant for the dependencies, I never speak about them for the other relations


Sorry! I think I just got carried out, I start writing these stereotypes to all my long class name relations (dependencies, generalisations, realisations, etc) to get an alias and use it.

It works in every case and that is very comfortable to model and code applications, since I don't have to create for example a dependency with stereotype use to get an alias for the parent class and another dependency to get an alias for the realisation.

To achieve this:
Code: Select all
<?php

namespace SomeNS;

use A\B\C\D;
use X\Y\Z;

class E extends D implements Z {
    //...
}


You just add stereotype use to the generalisation and realisation :)

In case a required_once is generated out of a dependency, the fact you have a dependency stereotyped use or use-as AZE changes nothing, the required_once is still generated

If the require_once was generated by a dependency and you modify this dependency to set its stereotype to use or use-as AZE, of course the required_one is not any more generated. To have both of them you need two dependencies


This is understandable using a dependency with stereotype use or use-as just to get the use statement :mrgreen:

As you can see in the historic of the 7.1.3 there is no new version for the reverse nor roundtrip. While the reverse/roundtrip do not create dependencies for use and use-as forms but put them in the textual definition of the artifacts it is normal and expected the roundtrip deletes them

Again the stereotypes use and use-as are only relevant for dependencies


My bad to try use and use-as on everything :oops:

I did not remember that I was doing this for other kind of relations :roll:
It is strange I do not allow ${comment} or ${description} in place of the complicated alias way :?


Well, again I got carried out and add use and use-as to everything and I thought: "What if I can add a description here? maybe I can type something in the relation/dependency/generalisation/etc description and add it as a comment for the use?"

-----
Having said that, I understand that it was meant only for dependencies, but it really helps a lot and it's easier to implement if you can also stereotype realisations and generalisations to get the use alias, because if there is one of those, it means that the class name you are aliasing it's written in the code, for associations you may or may not write the class name it in the code.

Besides, it's working (with the full class path name exception) if you are using autoloaders and you do not need the 'require_once' which is my case.

Thank you :)

Regards,
Federico.

Re: PHP use and namespaces

PostPosted: Tue 24 Oct 2017 15:15
by Bruno Pagès
fbernoldi wrote:I don't know why, the docs state that you have to use full class path when importing: http://php.net/manual/en/language.namespaces.importing.php

I will fix that

fbernoldi wrote:... it really helps a lot and it's easier to implement if you can also stereotype realisations and generalisations to get the use alias.

For me this is a dirty choice, the production of the use(-as) is global to the file, to put it on for instance a generalization would only make sense if the scope of the use was limited to that generalization

Re: PHP use and namespaces

PostPosted: Tue 24 Oct 2017 19:25
by fbernoldi
For me this is a dirty choice, the production of the use(-as) is global to the file, to put it on for instance a generalization would only make sense if the scope of the use was limited to that generalization


It's that or have a dependency to the parent class with the stereotype use, it's not quite clean either way.

Anyways, both ways are way better than have extremely long class names or harcoding "use" on the artifacts or using @{use} or something.