Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thoughts and feedback about AOP #154

Open
lisachenko opened this issue Jul 8, 2014 · 53 comments
Open

Thoughts and feedback about AOP #154

lisachenko opened this issue Jul 8, 2014 · 53 comments

Comments

@lisachenko
Copy link
Member

If you are using an AOP or have a plan to use it, please add a small comment here or just put a +1 ) I will be happy to see that this technique can be useful for you )
You can also provide an additional information about the usage (how you use it and where). I can put this information later on my site with hyper-link to your solution.

@JeyDotC
Copy link

JeyDotC commented Jul 8, 2014

Hello @lisachenko, here is a use case I've been thinking about:

Dependency injection

I've a proof of concept of dependency injection with Aura DI (Which I'll upload soon and obviously put a link here) if one's DI aspect is well designed, the backend library can be anything from AuraDI to Laravel to Symfony, etc.

Your classes would need to declare dependencies by just fulfilling the pointcuts configured in your aspect:

<?php
/**
* @ThisClassNeedsDI() !
*/
class MyClass {
    function __construct(SomeOtherClass $dependency){}
}

or

<?php
class MyClass {
    /**
    * @InjectSomethingHere(id="some_di_key") !
    */
    protected $iNeedAnInjection;
}

The advantages I see here are the proxies, nothing on reflection or things like that, just your dependency-resolving code injected in the right spots.

With the right aspects, GoAOP can even be the core for an IOC container :)

@lisachenko
Copy link
Member Author

@JeyDotC Thank you for the feedback! Really interesting use case.

We can extend it by providing virtual composer packages, eg something/di-aware and real implementations for symfony2, zend that provide something/di-aware and build a bridge with an aspects to the concrete framework. BTW, I had the same idea earlier and wanted to rewrite lisachenko/warlock to be a bridge between SF2.3 DI )

@alekciy
Copy link

alekciy commented Jul 10, 2014

+1

@TheCelavi
Copy link
Contributor

I have a contest of the problem which can be properly solved with AOP only. After research, I am stunned that PHP does not supports AOP in its core! AOP is MUST HAVE for PHP to compete with modern programming languages.

@lisachenko
Copy link
Member Author

AOP is MUST HAVE for PHP to compete with modern programming languages.

Yes ) It would be cool, but at the moment there is no implementation for the core, however there was a try: http://code.google.com/p/yaxx/source/browse/trunk/php/zend_language_parser.y?r=2#314

So, only real solutions are: FLOW3 with AOP, JMSAopBundle for Symfony2, Ray.AOP, my framework and AOP-PHP extension (unfortunately, not compiling for PHP>=5.5). But we need our community to move AOP forward, because PHP is a great tool and we can use it power together with AOP.

Thank you for supporting AOP in PHP, @TheCelavi

@bgaillard
Copy link

Hi, we principaly use AOP to configure transactions around our service Layers.

This is a standard practive in Java and it works too using PHP / Go AOP.

It allows to have a clean service layer without the need to manually begin / commit / rollback transactions, so it prevents spaghetti code / transaction coding errors.

For example :

class UserService implements IUserService {

    /**
     * The Data Mapper used to manage users persistence.
     * 
     * @Inject
     * @var \Application\Dal\DataMapper\UserDataMapper
     */
    protected $userDataMapper;

    /**
     * {@inheritdoc}
     */
    public function save(User $user) {

        // Multiple database create / read / update operations inside one transaction...

    }
}

Then we define the following (simplified here) TransactionAspect class :

class TransactionAspect implements Aspect {

    /**
     * The Zend Database Adapter to be used to manage transactions to the database.
     *
     * @var \Zend\Db\Adapter\AdapterInterface
     */
    private $dbAdapter;

    /**
     * Method called around service functions which have to be transactional.
     *
     * @param \Go\Aop\Intercept\MethodInvocation $methodInvocation an object which represents the service method which
     *        is called.
     * 
     * @Around("execution(public Application\Service\Impl\*Service->create*(*)) || execution(public Application\Service\Impl\*Service->delete*(*)) || execution(public Application\Service\Impl\*Service->save*(*)) || execution(public Application\Service\Impl\*Service->update*(*))")
     * 
     * @throws \Exception if an exception is encountered in the wrapped service function.
     * 
     * @return mixed the return of the function associated to the join point.
     */
    public function around(MethodInvocation $methodInvocation) {

        $this -> dbAdapter -> getDriver() -> getConnection() -> beginTransaction();

        try {

            $ret = $methodInvocation -> proceed();
            $this -> dbAdapter -> getDriver() -> getConnection() -> commit();
            return $ret;

        } catch (\Exception $exception) {

            $this -> dbAdapter -> getDriver() -> getConnection() -> rollBack();
            throw $exception;

        }

}

We also used https://github.com/AOP-PHP/AOP the same way in one of our project. But as the project is not really maintained we're planning to abandon it by using Go AOP instead.

Sadly AOP-PHP is a C extension which seems to be hard to maintain (few developers produce good quality code in C or even understand the C language) and it does not work under Windows without modifications in the build scripts / sources.

So thanks @lisachenko for this great framework !

👍

@baptistepillot
Copy link

+1 I wrote my own AOP implementation, massively inspired by the techniques you used - thanks a lot -, into my framework. It allows me to design getters and setters in php, to write modular plugins without having to tell the core they may exist... I am convinced AOP is a must-have for high level programming languages now, a plus for huge structured applications.

Thanks a lot for your work.

@lisachenko
Copy link
Member Author

Oh, thank you, @bgaillard and @baptistepillot! You just give me a feeling that my work is useful and I can continue development. Without feedback for many months my motivation to work on AOP were decreased to very low level. I even had a thoughts about is it really needed by developers or not.

So many developers think that AOP is not for "true" OOP programmers and their negative comments can not help me with building more transparent and flexible library. But I looking forward for AOP community that can work together and share thoughts and examples of the usage )

I'm also feel honored that my framework can be a replacement for AOP-PHP extension, because this means that Go! AOP framework is more stable and fast enough to be used in production without worrying about speed.

So, thanks a lot for supporting me with feedback! 👍

@bgaillard
Copy link

Hi @lisachenko,

Without feedback for many months my motivation to work on AOP were decreased to very low level. I even had a thoughts about is it really needed by developers or not.

I'm working with PHP since only 2 years now. I came from the Java world and when I started to code with PHP I had a lot of questions but few of the PHP developers I knew at the moment could respond to me. Questions like "How do you automatically manage transactions ?", "Argh, this peace of code is ugly, how do you work with your collegues now ?", "Is their any solid Dependency Injection framework available ?", "Do you use something like Checkstyle to verify coding standards", "How do you manage dependency versions ?" etc...

In my opinion PHP is maturing because several tools and best practices used to respond to those questions emerged the last 2 / 3 years (PSRs, composer, PHPUnit, CodeSniffer, PHP-DI, PhpDocumentor, etc...).

But we already had all those tools and practices in Java since 5 / 10 years (Maven, JUnit, Checkstyle, Spring, Javadoc, etc...) !

AOP is something well known by Java developers, but most PHP developers simply do no know it exists yet ! In my opinion AOP is an almost vital feature needed by a well written PHP web application but sadly PHP devs do not know it or how / where to use it :-(

So many developers think that AOP is not for "true" OOP programmers and their negative comments can not help me with building more transparent and flexible library. But I looking forward for AOP community that can work together and share thoughts and examples of the usage )

Our applications uses AOP only at few places in the code, I rarely saw an app which extensively used AOP. In my opinion AOP should be used for specific use cases only and it clearly not "breaks" OOP. It helps prevent spagetti / redondant peaces of code on large apps and it definitly helps to produce clean, readable and good quality code (for the sceptics see this article http://veerasundar.com/blog/2010/01/use-cases-of-aspect-oriented-programming).

This is perhaps what we have to explain more to gain much more traction from the PHP community.

Thanks again and please don't give up :-) !

@lisachenko
Copy link
Member Author

AOP is something well known by Java developers, but most PHP developers simply do no know it exists yet !

Yes, unfortunately, it's true. But I can see increasing number of visits on go.aopphp.com as well as the number of repo cloning. And it's a good sign for me :)

@carlosgoce now doing a great job by writing an articles about the usage of AOP (Spanish language): http://blog.carlosgoce.com/simplifica-tus-transacciones-en-laravel-con-anotaciones-aop/ and
http://blog.carlosgoce.com/realizando-cache-con-aop-en-laravel-4/

In my opinion AOP should be used for specific use cases only and it clearly not "breaks" OOP. It helps prevent spagetti / redondant peaces of code on large apps and it definitly helps to produce clean, readable and good quality code (for the sceptics see this article http://veerasundar.com/blog/2010/01/use-cases-of-aspect-oriented-programming).

Entirely agree with you that AOP is a special tool for solving special issues with spaghetti code. And it's perfectly extend OOP with new techniques.

I will keep working on this project to make it better, faster and mature )

@JeyDotC
Copy link

JeyDotC commented Aug 26, 2014

Another possible usage could be a port of C#'s Insight Database which has a feature in which one can define an interface (namely a repositry) and it generates the implementation at runtime.

Go! AOP may provide a good way to implement it, is something to be discussed :)

@crisp-github
Copy link

Using it for logging now - thanks! Would like to know if there is a way to only consider methods defined in the file where an annotation is ? Or some way to achieve same. We don't want to log methods from base classes. Cheers!

@lisachenko
Copy link
Member Author

@crisp-github can you provide your pointcut expression for logging? You can build any complex pointcuts with logical &&, || and ! operators. For example, mark a class with an annotation and then match only public methods in this class.

@markNZed
Copy link

@lisachenko thanks. Currently doing this:

public function isDeclaredInClass(MethodInvocation $invocation)
    {
        $obj        = $invocation->getThis();
        $class      = is_object($obj) ? get_class($obj) : $obj;
        $method     = $invocation->getMethod();
        $declaringClassName = $method->getDeclaringClass()->name;

        // If the method is not declared in the same class then we don't log it
        // reduced noise.
        $length = strlen($class);
        $match = (substr($declaringClassName, 0, $length) === $class);

        return $match; 
    }

@csrinaldi
Copy link

@lisachenko Excelent framework!!!
Have you any implementation of Symfony2 DI integration?

@lisachenko
Copy link
Member Author

@csrinaldi thanks! I have such an implementation in Warlock: https://github.com/lisachenko/warlock But now I doesn't support it, because of lack of time. Need more contributors or free time to keep it up-to-date with goaop itself. However, it's easy to update it, so if someone will ask me for that, I'll be able to update it.

One more reason, why I don't improve this kind of integration is a fact that Symfony has a JMSAopBundle and DiC container can do this work (AOP) in more transparent way without brutal magic with autoloader, stream wrapper and on-fly code generation.

@TheCelavi
Copy link
Contributor

I am still thinking about approach which is good enough as C extension PHP-AOP (full support) -> and I told you that maybe compiling the class and intercepting autoloading is answer which can provide us with full support for AOP in PHP.

You told me that it will make debugging harder since breakpoints must be set on compiled classes, not the original ones. It is a valid point.

I just wondering if that is good decision - to scarify full AOP support in benefits of putting debug break points into original classes, or to have compiled classes with AOP annotations but to ask from developers that for those classes put breakpoints into compiled classes?

I can not shake the feeling that inconvenience of this debugging (which is easy to handle) is good compromise in order to have full AOP support.

What say you?

@lisachenko
Copy link
Member Author

@TheCelavi could you describe what do you mean by "full AOP support"? AOP it is just a paradigm, it can not be full or not. There are several possible ways of implementing AOP in PHP and framework just implements one of them.

I know about some limitations of current approach, but they are not critical and can be easily solved, whereas opcache and xdebug support is most important features, especially for production performance optimization. I don't have a plans to change decorators with anything, including direct code modification, but you can try to define a custom SourceTransformer and implement direct weaving logic 😃 (AspectMock uses this technique with custom filter to perform direct weaving into the source code)

@TheCelavi
Copy link
Contributor

Well, I do not like to have AOP in Symfony2 supported only for services... Per example, I want to use AOP for caching of some method execution for model classes:

$user->getRoles()

GO-AOP can not support this, right? Nor any other solution as well, except PHP-AOP, which does not compile on PHP 5.4?

@lisachenko
Copy link
Member Author

GO-AOP can not support this, right? Nor any other solution as well, except PHP-AOP, which does not compile on PHP 5.4?

@TheCelavi goaop can be easily used with models, doctrine entities or anything else. Just describe a valid pointcut for that and attach an advice. For example, AOP can be used to create lazy-loading for properties in models or cache property value in the memcache.

@workingflows
Copy link

@lisachenko I made a humble integration with Symfony2 and detects whether the "Debug::enable" in Symfony2, AOP generates nothing in cache, so nothing works.

So if one modifies "AopComposerLoader::init ()" adding:

if (is_array ($ loader) && $ loader [0] instanceof DebugClassLoader) {
     $ loader [0] = $ loader [0] -> getClassLoader ();
     $ loader [1] = 'loadClass';
}

everything works. The problem is that this modification is in the library and one is bound.

Therefore, I extended AopComposerLoader, overriding the method init() and from my own kernel, within the init method call my own AopCompoerLoader.

But unfortunately this does not work, and do not understand why, because it's inheritance ...

The second problem is that if one starts Symfony in app.php:

$ kernel = new AppKernel ('prod', false);

must force the following settings:

orm:
         auto_generate_proxy_classes: true

Because otherwise Doctrine proxies are not generated.

Any ideas on AopComposerLoader?

@lisachenko
Copy link
Member Author

Hi, @workingflows!
Symfony and Go! AOP itself are too complex frameworks ) There are a lot of hidden issues and tricks that can break a lot of things, so I even decided to recommend JMSAopBundle for Symfony.

However, frameworks can be integrated with some fixes in the source code.

  1. Symfony's DebugClassLoader class is not polite and tries to replace everything without checking if this is an original class or not, hence a conflict, because both of loaders tries to do the same job. This issue can be fixed by hand or with some tricks in the kernel (method override, etc)
  2. What is wrong with auto_generate_proxy_classes. I'm not faced this issue earlier, maybe you can create a separate issue for that so we we willl be able to discuss it?

@RayBenefield
Copy link

I wanted to put a little note here. I am working on a new PHP ORM heavily focused around using annotations, introductions, and other details to allow developers to string together a pseudo ActiveRecord pattern onto domain objects without requiring domain objects to extend an ActiveRecord Model. Theoretically this should allow domain objects to take full advantage of OOP inheritance for their domain objects and neatly unit test them since AOP can introduce a pseudo multi-inheritance setup. The goal is tying a marker interface for a Model or an annotation and have all the code automatically weaved into the domain models to give them access to a related persistence model without tainting the source code of their domain.

The company I work for has been using Laravel and Eloquent, and when they tasked me with extending Eloquent to support Couchbase and Elasticsearch as a data source we ran into a lot of issues as everything was very coupled together. I felt there had to be a better way to handle an ORM while still keeping it easy to use, but more extendable without MASSIVE god feeling objects.

I discovered Go! AOP when we decided to add AspectMock to mock out the static method calls of Eloquent and to mock php global functions. And I figured data persistence definitely feels like a crosscutting concern so I explored the possibility of just making data persistence an aspect that can be weaved into domain objects. At the same time I've discovered ActiveRecord being seen as an anti-pattern in terms of Domain Driven Design, but I think if I do it right I can merge the benefits of ActiveRecord with the Data Mapper pattern to make something more powerful that conflicts with DDD less. I'm still rather new to AOP, the concepts that make a good ORM, SOLID principles, and DDD, but I'm optimistic and it seems doable.

I'm enjoying what I've played with so far and am working on the project in a private bitbucket repo and when I get a working implementation from start to finish, then I'll definitely share it to the public. This is really my first attempt at an open source project so it is a wee bit daunting hence the private repo.

@lisachenko
Copy link
Member Author

Thank you, @GodlyPerfection! Occasionally missed a notification from GitHub about new post here and just discovered it.

I am impressed by your description and hope, that you will be able to use AOP framework to build one more tool that will be simple to use and respects DDD principle, because DDD is closely relates to AOP and clean code of domain model.

I can tell you that I have a secret ideas about powerful ORM too, based on my framework and property interceptors for implementing lazy loading and many-to-many mapping ) But I haven't free time now to implement this framework. But if you want to work on this, we can discuss this together somewhere (skype, chat, IRC, etc)

I wish you good luck and hope that you show your tool soon! Thanks for choosing AOP framework and trying it.

@RayBenefield
Copy link

No, thank you @lisachenko for the work you've put into this and your continued efforts. Seeing efforts to ensure compatibility with PHP 7 is very comforting.

It's good to hear that I'm not the only one that thinks an ORM in AOP could be very powerful. I'll get in touch more once I have an end-to-end demonstration ready. Hopefully it won't be too long. I appreciate you reaching out and look forward to bouncing ideas off of you and sharing quality design discussions. I'd love to hear some of your ideas once I can show that I have something to deliver.

My skype is also GodlyPerfection in case you wanted to touch base a little sooner.

Thanks again for all the work you've done so far.

@andrewnester
Copy link

+1, is it compatible with PHP7?

@dgafka
Copy link

dgafka commented Aug 19, 2015

big +1. And what about PHP7 compatibility?

@lisachenko
Copy link
Member Author

@andrewnester @dgafka there is a task #175, which tracks the compatibility issues in framework with 5.6/7.0. However, there is a one big stopper: outdated Php-Token-Reflection library, which isn't maintained now and restricted only to the php5.5 syntax.

I'm waiting for @asgrim and @Ocramius BetterReflection (https://github.com/Roave/BetterReflection) library, which can be a good replacement.

As for general compatibility, framework core is stable and can be used on any PHP platform, starting from 5.4, however several features can be unavailable (return typehinting, variadic functions, etc)

@Ocramius
Copy link

Note that BetterReflection is at a good point, but we still want to get compatibility with the PHP-SRC .phpt suite before going 1.0.0.

@lisachenko
Copy link
Member Author

@Ocramius 👍

@gmorel
Copy link

gmorel commented Sep 18, 2015

👍

2 similar comments
@Dbuggerx
Copy link

+1

@rockiebond
Copy link

+1

@kukoman
Copy link

kukoman commented Jan 5, 2016

👍 and thank you for your hard work!

@ifeltsweet
Copy link

Biggest +1 I have ever given. Thank you!

@schlessera
Copy link
Contributor

+1 here too. Have started using Go! AOP for logging within a larger codebase, and will now add caching too. Your framework has been wonderful so far!

@lisachenko
Copy link
Member Author

Thanks to everyone! BTW, if you use PhpStorm for developing, then you should install a plugin "Go! AOP Framework" to have a real fun and control over the AOP in your application!

@findli
Copy link

findli commented Apr 16, 2016

I like use codeception/AspectMock, that uses GoAOP that uses http://andrewsville.github.com/PHP-Token-Reflection/ which not maintained for at least a year. With PHP 7 it cause errors.
Suggest: https://github.com/Roave/BetterReflection instead.

@lisachenko
Copy link
Member Author

@findli FYI, the latest version of framework uses the goaop/parser-reflection package and it is fully PHP7 compatible. See Codeception/AspectMock#92 and ping @DavertMik to update the dependency )

@GulDmitry
Copy link

@lisachenko, it would be nice to have AOP with php 7.1. The framework seems ready (according to travis), but the parser "nikic/php-parser": "^1.2|^2.0" which is dependency for goaop/parser-reflection supports new syntax only in 3.x version.

@lisachenko
Copy link
Member Author

@GulDmitry wait a little bit ) I'm preparing changes right now

@GulDmitry
Copy link

Thanks a lot. And don't forget about the symfony bundle. 😄

@lisachenko
Copy link
Member Author

@GulDmitry dev-master (aka 2.0-dev) now supports PHP7.1 features: nullable types, void return type and all new grammar, thanks to the @nikic nikic/php-parser: ~3.0 😃

@i3anaan
Copy link

i3anaan commented Jul 24, 2017

Applying it to tackle handling permissions in our online member system.

@Rastusik
Copy link
Contributor

+1

@pthpth
Copy link

pthpth commented Mar 19, 2018

Hi I want to use this library but I didn't find any book or a tutorial which will teach this framework and aop concept step by step as I am a beginner it is very difficult to learn through tutorial available

@lisachenko
Copy link
Member Author

@anil260470 you could start with http://readthedocs.org/projects/go-aop-php/downloads/pdf/dev/ documentation to learn some information about AOP

@dumith-eranga
Copy link

+1

@imanghafoori1
Copy link

I want to leverage this amazing package in my laravel package :

https://github.com/imanghafoori1/laravel-HeyMan/
to authorize the user when a method is called for example.

@lisachenko lisachenko pinned this issue Jan 4, 2019
@lisachenko lisachenko changed the title Survey: do you want to use AOP? Please, give a feedback. Thoughts and feedback about AOP Jan 4, 2019
@eeliu
Copy link

eeliu commented Jan 25, 2019

Thanks for your excellent project ! @lisachenko

@l00k
Copy link

l00k commented Aug 11, 2019

@lisachenko Again! This is awesome project. How can I buy you a beer?

@eeliu
Copy link

eeliu commented Aug 12, 2019

@lisachenko +1 👍

@FloSew
Copy link

FloSew commented Feb 12, 2020

Very happy to have found your project. I'll give you context: in our legacy project which is part of the frontend of a big telecommunication company in France, we were looking for a way to implement distributed tracing for APM. Our code base is very huge and the first priority was to avoid modifying every methods. With your framework we have a big hope that we can do it using the annotation so that we can execute tracing before and after each method without impacting every file and passing a lot of time on it. I'll keep you posted on our tests but it really feels like a life saver!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests