Welcome Guest, Not a member yet? Register   Sign In
Events Library
#1

(This post was last modified: 04-23-2015, 04:42 AM by dmyers.)

Here is a events library (included with the example application) which I created.


https://github.com/dmyers2004/ci-events-example

I plan on releasing a super stripped down version of my basic framework sometime soon but, I figured people could use this now.

I also cross posted this to the CI4 events thread so please don't yell at me!

DMyers
Reply
#2

Nice one man....and keep making more libraries.
Reply
#3

Quote:public trigger($name,&$a=null,&$b=null,&$c=null,&$d=null,&$e=null,&$f=null,&$g=null,&$h=null);

This just makes me wonder, why eight? Why not just ($name, &$data)?
Reply
#4

(04-27-2015, 08:06 AM)mwhitney Wrote:
Quote:public trigger($name,&$a=null,&$b=null,&$c=null,&$d=null,&$e=null,&$f=null,&$g=null,&$h=null);

This just makes me wonder, why eight? Why not just ($name, &$data)?

By just passing in a single variable ($data) in your listeners you would need to take it apart AND put it back together as needed or you would need to hand around the reference to the $data array and access your multiple variables by key.


I think my way it's cleaner and more descriptive code

If you passed in a single array it would be:

$ci->event->register('user.login',function(&$data) {
$data['user_name'] = (isset($data['user_name'])) ? $data['user_name'] : '';
$data['user_id'] = (isset($data['user_id'])) ? $data['user_id'] : '';
$data['user_email'] = (isset($data['user_email'])) ? $data['user_email'] : '';

$data['user_name'] = $data['user_id'].' '.$data['user_email'];
});

$ci->event->trigger('user.login',['user_name'=>$username,'user_id'=>$user_id,'user_email'=>$user_email]);

Using this method you also really have no idea if they even sent in a necessary variable name as a array key without properly testing for it or it will throw a PHP error if you try to access it without testing it and it's not sent in

Severity: Notice
Message: Undefined index: user_name

By using multiple input/outputs in the listeners/triggers you can write your closure arguments a little more descriptive and usually write less code.

$ci->event->register('user.login',function(&$user_name,&$user_id,&$user_email) {
$user_name = $user_id.' '.$user_email;
});

$ci->event->trigger('user.login',$user_name,$user_id,$user_email);

Even if $user_id isn't sent in (and therefore null) it won't throw a error.

If you need to send in more than eight you could always make the last 1 an array but I usually try to keep my trigger functions "light" to keep them fast and haven't run into a problem with only having 8. 6 is where I begin to feel the complexity of the trigger might be to high for a trigger. I am usually at 3 or 4 and just thought I should double it to be "safe". Your mileage may vary.

I updated my code to include these examples

DMyers
Reply
#5

Generally, when creating an event, the expected parameters should be defined and made available any time that event is triggered. If the payload of the event doesn't match the definition, there should be an error when the subscriber is triggered and can't access the expected information. In the worst case, you sanitize the payload before triggering the event (or don't trigger it when the required data isn't available), rather than sanitizing the data within each subscriber.

I think you'll find, in time, that you're still degrading performance by checking for null inputs in your subscribers (and, if a subscriber doesn't do so, you may still get an unhandled exception).
Reply
#6

(04-28-2015, 08:44 AM)mwhitney Wrote: Generally, when creating an event, the expected parameters should be defined and made available any time that event is triggered. If the payload of the event doesn't match the definition, there should be an error when the subscriber is triggered and can't access the expected information. In the worst case, you sanitize the payload before triggering the event (or don't trigger it when the required data isn't available), rather than sanitizing the data within each subscriber.

I think you'll find, in time, that you're still degrading performance by checking for null inputs in your subscribers (and, if a subscriber doesn't do so, you may still get an unhandled exception).

I wanted to make my event library fast and use the least amount of memory as possible and therefore didn't feel the extra overhead to register the expected variables and the expected types (one or more) as well as verifying the input when it's sent in to make sure it matches the expected variables and types would be worth that overhead.

I say multiple types because $user_id = '123' & $user_id = 123 & $user_id = null are all valid options in my example code.
Any "automatic" validator on $data should allow this as well.

Heck mine actually could be used in a method overloading fashion if you wanted:

$array_of_people = ['joe','john'];
ci()->event->trigger('add_people',$array_of_people);

$single = 'joe';
ci()->event->trigger('add_people',$single);

This should valid as well no?

I'm not saying you couldn't add more functionality to the library just that it wasn't the goal of my library. 

Also I'm not sure what you mean by the following:

"and, if a subscriber doesn't do so, you may still get an unhandled exception)."

I have full error_reporting(-1) (codeIgniter Default for development) in index.php


and it doesn't throw a unhandled exception? maybe my version of PHP (5.5.17) handles it differently.

$user_name = null; is a complete valid statement

I would be interested in comparing your library with mine in regards to speed and memory.



Don Myers
Reply
#7

(04-28-2015, 02:40 PM)dmyers Wrote: I wanted to make my event library fast and use the least amount of memory as possible and therefore didn't feel the extra overhead to register the expected variables and the expected types (one or more) as well as verifying the input when it's sent in to make sure it matches the expected variables and types would be worth that overhead.

I'm not saying that the library itself needs to be aware of and/or enforce these requirements. The code which calls your library to trigger an event should ensure the data is valid according to whatever documented specification exists for that event before triggering it. In theory, any code subscribing to that event is using the same specification. All of this assumes a situation in which it is more important to be fast and use the least amount of memory possible, because the alternative would be to define an interface or abstract class for the event's payload (so the structure of the data would be enforced by the interface/class definition).


(04-28-2015, 02:40 PM)dmyers Wrote: I say multiple types because $user_id = '123' & $user_id = 123 & $user_id = null are all valid options in my example code.
Any "automatic" validator on $data should allow this as well.

Heck mine actually could be used in a method overloading fashion if you wanted:

$array_of_people = ['joe','john'];
ci()->event->trigger('add_people',$array_of_people);

$single = 'joe';
ci()->event->trigger('add_people',$single);

This should valid as well no?

If that flexibility is desired in that particular event, the event's payload should be defined as such. Otherwise, your subscriber will be expecting the payload to be an array and will receive a string. If it doesn't check the type of the argument, it may well trigger an exception by treating the string as an array (or, worse, it may silently manipulate the string in unexpected ways).

None of this is changed by passing more arguments to the function. Further, if any given variable in your string of arguments can be of multiple types, you start to lose the performance improvement you claim to gain by passing multiple arguments, because each subscriber has to check the type of any variable which might require different treatment based on type.

(04-28-2015, 02:40 PM)dmyers Wrote: Also I'm not sure what you mean by the following:

"and, if a subscriber doesn't do so, you may still get an unhandled exception)."

I have full error_reporting(-1) (codeIgniter Default for development) in index.php


and it doesn't throw a unhandled exception? maybe my version of PHP (5.5.17) handles it differently.

I meant "unhandled exception" in the sense that you're relying on CodeIgniter's exception handler to catch it, rather than preventing it in the first place or catching it yourself.

If a subscriber is expecting $e to be an array, receives null, and doesn't check is_null($e) or is_array($e) (or whatever type checking you choose) before applying certain functions to $e, you're going to end up with an exception.

(04-28-2015, 02:40 PM)dmyers Wrote: I would be interested in comparing your library with mine in regards to speed and memory.

I'm simply speaking in general terms, but you can look at the majority of mature PHP event libraries and find that most of them use 2 or 3 arguments in their trigger methods: the name of the event, the payload, and maybe an argument to prevent event bubbling (for libraries modeled on the HTML/JavaScript DOM style of event handling).

I haven't profiled Bonfire's Events library, but that's primarily because it hasn't attracted my attention when profiling problematic pages (I didn't write the library, either, but there's not much stopping me from rewriting it if I see a reason to do so). It operates on an assumption that the subscriber may be in a file which is not loaded until the event is triggered, which may create its own performance trade-offs. This also precludes the possibility of using a closure as a subscriber, though it probably wouldn't be difficult to add that option.
Reply
#8

(04-29-2015, 10:44 AM)mwhitney Wrote:
(04-28-2015, 02:40 PM)dmyers Wrote: I wanted to make my event library fast and use the least amount of memory as possible and therefore didn't feel the extra overhead to register the expected variables and the expected types (one or more) as well as verifying the input when it's sent in to make sure it matches the expected variables and types would be worth that overhead.

I'm not saying that the library itself needs to be aware of and/or enforce these requirements. The code which calls your library to trigger an event should ensure the data is valid according to whatever documented specification exists for that event before triggering it. In theory, any code subscribing to that event is using the same specification. All of this assumes a situation in which it is more important to be fast and use the least amount of memory possible, because the alternative would be to define an interface or abstract class for the event's payload (so the structure of the data would be enforced by the interface/class definition).



(04-28-2015, 02:40 PM)dmyers Wrote: I say multiple types because $user_id = '123' & $user_id = 123 & $user_id = null are all valid options in my example code.
Any "automatic" validator on $data should allow this as well.

Heck mine actually could be used in a method overloading fashion if you wanted:

$array_of_people = ['joe','john'];
ci()->event->trigger('add_people',$array_of_people);

$single = 'joe';
ci()->event->trigger('add_people',$single);

This should valid as well no?

If that flexibility is desired in that particular event, the event's payload should be defined as such. Otherwise, your subscriber will be expecting the payload to be an array and will receive a string. If it doesn't check the type of the argument, it may well trigger an exception by treating the string as an array (or, worse, it may silently manipulate the string in unexpected ways).

None of this is changed by passing more arguments to the function. Further, if any given variable in your string of arguments can be of multiple types, you start to lose the performance improvement you claim to gain by passing multiple arguments, because each subscriber has to check the type of any variable which might require different treatment based on type.


(04-28-2015, 02:40 PM)dmyers Wrote: Also I'm not sure what you mean by the following:

"and, if a subscriber doesn't do so, you may still get an unhandled exception)."

I have full error_reporting(-1) (codeIgniter Default for development) in index.php


and it doesn't throw a unhandled exception? maybe my version of PHP (5.5.17) handles it differently.

I meant "unhandled exception" in the sense that you're relying on CodeIgniter's exception handler to catch it, rather than preventing it in the first place or catching it yourself.

If a subscriber is expecting $e to be an array, receives null, and doesn't check is_null($e) or is_array($e) (or whatever type checking you choose) before applying certain functions to $e, you're going to end up with an exception.


(04-28-2015, 02:40 PM)dmyers Wrote: I would be interested in comparing your library with mine in regards to speed and memory.

I'm simply speaking in general terms, but you can look at the majority of mature PHP event libraries and find that most of them use 2 or 3 arguments in their trigger methods: the name of the event, the payload, and maybe an argument to prevent event bubbling (for libraries modeled on the HTML/JavaScript DOM style of event handling).

I haven't profiled Bonfire's Events library, but that's primarily because it hasn't attracted my attention when profiling problematic pages (I didn't write the library, either, but there's not much stopping me from rewriting it if I see a reason to do so). It operates on an assumption that the subscriber may be in a file which is not loaded until the event is triggered, which may create its own performance trade-offs. This also precludes the possibility of using a closure as a subscriber, though it probably wouldn't be difficult to add that option.



If you are unhappy with the library simply choose another one.

https://packagist.org/search/?q=event

I just thought I would give something back to the PHP / CodeIgniter community. I never planned on getting into a discussion about this choice Vs that choice.

I am sure everyone knows there are a ton of other event libraries out there (see link above) and every single one approaches the same problem from a different angle. Mine is simply another such angle.

I was planning on releasing more of my code to the community but I guess I forgot how much additional work is required defending every single decision one makes in comparison to millions of other people. Just for a single library of less than 30 lines it's already starting to feel like a "this framework Vs that framework" debate.

I would be interested in looking at the library you currently use in your applications.

But my library is what it is take it or leave it.

DMyers
Reply
#9

(This post was last modified: 04-30-2015, 09:26 AM by mwhitney. Edit Reason: grammar )

I apologize. I didn't intend to make you feel that you (or your code) were under attack.

I tend to take an interest in the decisions which lead to code being written in a particular way, and long argument lists on function definitions tend to trigger that interest.

To answer the question of which library I currently use, it can be found here:
https://github.com/ci-bonfire/Bonfire/bl...Events.php

It's a portion of Bonfire that is often overlooked (and probably underused), and I have often considered looking at various options to update it. However, it performs well enough that it doesn't get my attention (and looking at that code listing in GitHub's web interface, it probably needs a little formatting/cleanup). Like a lot of Bonfire's core code, it's probably also not isolated enough to be readily used in projects which don't use Bonfire.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB