Optimize this PHP Code? - php

I am currently working on a mashup that incorporates many data feeds. In order to display ALL of the feeds that the user wants on one page, I am currently using if statements to cross-check with the MySQL database like this:
if($var["type"]=="weather")
$var being the result of a call to mysqli_fetch_array
and then including code relevant to the function (e.g. weather) underneath, and then another "if" statement for another feed, so on so on. The problem is that there will be many feeds, and having all these "if" statements will be slow and redundant.
Is there any way to optimize this PHP code?

Another solution might be to map the "type" to a custom function using associative arrays.
e.g. (pseudo code)
function handle_wheater_logic() {
// ... your code goes here
}
function handle_news_logic() {
// .. your code goes here
}
$customFunctions = array("wheater" => "handle_wheater_logic", "news" => "handle_news_logic");
while ($row = mysql_fetch_...) {
call_user_func ($customFunctions[$row["type"]])
}
This would eliminate the need to use a lot of if statements. You might as well do the "type to function" mapping in a configuration file or maybe just store the name of the custom function to call for each "type" in a database table - that's up to you.
You can, of course also pass parameters to custom function. Just checkout the documentation for call_user_func[_array].

Try this:
$methods = array(
"weather" => function() {
// code
},
"otheroption" => function() {
}
);
Just use then $var["type"] as a index in the array to get the function:
$methods[$var["type"]]();
You can obviuosly, for better readbility do something similar:
$methods = array(
"weather" => "wheater_function",
"otheroption" => "other_function"
);
and then call the functions this way:
call_user_func($methods[$var["type"]]);
To be even more object oriented we can obviously store in the array objects implementing a particular interface, or store object redifining the __call() magic method and use it like functions.

You can use a switch statement.

A good solution for eliminating a lot of if statements and a huge switch statement just checking for one condition, would be to implement a design pattern such as the Strategy pattern.
This way you will have the code for each type separated, which makes it easier to overview and manage.
Here's an example of an implementation http://blogs.microsoft.co.il/blogs/gilf/archive/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements.aspx
Even if you won't implement this strictly it will give you some ideas on how to solve this elegantly.

Create an array that associates a function to each feed type:
$actions = array("weather" => "getWeather",
"news" => "getNews");
Then use call_user_func to call the correct one:
call_user_func($actions[$var["type"]]);

Polymorphysm for the rescue.
inteface FeedInterface {
public function retrieve($params);
}
class FeedWeather implements FeedInterface {
public function retrieve($params) {
//retrieve logic for weather feed
}
}
class FeedSports implements FeedInterface {
public function retrieve($params) {
//retrieve logic for sports feed
}
}
With use of PHP class autoloading, each of above declarations can be in a separate file, possibly namespaced as well. Then your feed retrieval code could look like this:
$class = 'Feed'.$var["type"];
$feed = new $class;
$feed->retrieve($params);
That's overly simplified and would need some additional code for error handling, discovery of non-existing classes and such, but the idea should be clear.

Using either an If Statement or a Switch statement will be faster than you care about. It might look ugly and be cumbersome to maintain but it will be fast.

Related

What is elegant solution for a PHP function with a lot of parameters?

I need to create a function that would insert user data into a "medical_records" table that has about 30 fields.
So the "classic" solution is writing something like:
function insert_medical_records($param1, $param2,..., $param30) {
// code here
}
But of coarse, such code writing is prone to errors and not elegant at all.
I thought of better solution like creating an array of parameters and passing its values to the function, but I don't quite know a valid syntax for that.
Or maybe there is a better solution then this altogether?
Thank you!
Since php has a soft type control, you can just give your function one input parameter. That parameter will be an array or an object.
In case of an array:
function insert_medical_records($input_array) {
// Here you can use $input_array['param1'], $input_array['param2'],
}
Before calling the function, you need to populate the array, something like:
$input_array['param1'] = "your param 1 value";
$input_array['param2'] = array('a' => 1, 'b' => 2);
insert_medical_records($input_array);
I would also suggest you to check the content of the input variable of the function:
function insert_medical_records($input_array) {
if (!isset($input_array['param1'])) {
// manage your error
return;
}
// Everything is ok. Do your stuff here...
}
Instead of isset, you should also consider using empty, is_array or array_key_exists. This it's up to your specific situation.
The solution using Object instead of Array is really similar. You define attributes such as $input_object->param1.
How about:
class MedicalRecords {
/* code here */
}
function insert_medical_records(MedicalRecords $mr) {
/* more code here */
}
and now you can add logic to do thing like validation on the records to the object itself and better seperate your code's concerns along more logical lines.

Include simple fields based on context in Fractal

I am using the Fractal library to transform a Book object into JSON by using a simple transformer:
class BookTransformer extends \League\Fractal\TransformerAbstract
{
public function transform(Book $book)
{
return [
'name' => $book->getName()
// ...
];
}
}
And I am performing the transformation as follows.
$book = new Book('My Awesome Book');
$resource = new \League\Fractal\Resource\Item($book, new BookTransformer());
$fractal = new \League\Fractal\Manager();
$fractal->setSerializer(new \League\Fractal\Serializer\ArraySerializer());
$json = $fractal->createData($resource)->toJson();
This works great. However, I have certain fields on my Book object that should not always be included, because this depends on the context the transformation is done in. In my particular use case, the JSON returned to AJAX requests from my public website should not include sensitive information, while this should be the case when the data is requested from an admin backend.
So, let's say that a book has a topSecretValue field, which is a string. This field should not be included in one transformation, but should be included in another. I took a look at transformer includes, and played around with it, but this only works with resources. In my case, I need to somehow include different fields (not resources) for different contexts. I have been digging around and could not find anything in the Fractal library that could help me, but maybe I am missing something?
I came up with a working solution, but it is not the prettiest the world has ever seen. By having a BaseBookTransformer that transforms fields that should always be included, I can extend this transformer to add fields for other contexts, e.g. AdminBookTransformer or TopSecretValueBookTransformer, something like the below.
class AdminBookTransformer extends BookTransformer
{
public function transform(Book $book)
{
$arr = parent::transform($book);
$arr['author'] = $book->getTopSecretValue();
return $arr;
}
}
This works fine, although it is not as "clean" as using includes (if it were possible), because I have to actually use a different transformer.
So the question is: is there anything in Fractal that enables me to accomplish this in a simpler/cleaner way, or is there a better way to do it, be it the Fractal way or not?

Simple way to replace a php switch statement in mustache.php?

I'm working on figuring out how to do common things with Mustache.php.
At this point, I'm trying to replace a native php switch statement in the template.
Given a "status" flag, e.g. 'A' for Active,
and a set of display options like A => Active, I => Inactive, P=>Pending, D=>Deleted,
how would I make a nice display string in Mustache.php by modifying the data in the template?
Example data for a table:
$users = array(
array('username'=>'william', 'status'=>'A', 'date_created'=>'7-01-2012'),
array('username'=>'john', 'status'=>'P', 'date_created'=>'5-17-2012')
);
The whole point of Mustache, is having your template clean from all logic. Mustache templates should be logic-less. This is quite a different and confusing methodology for newcomers.
To solve your problem, you will need to re-process the $users array to contain everything your Mustache template will need, before-hand. e.g. if the status field switch statement was intended for displaying a human-readable status, then your View class should look something like:
class View_User {
public $_users;
public function users()
{
$users = array();
foreach ($this->_users as $user)
{
$user->status_label = // Use your 'switch' statement here
$users[] = $user;
}
return $users;
}
}
Then all your Mustache template needs to do, is output {{status_label}} like so:
<ul>
{{#users}}
<li>Status: {{status_label}}</li>
{{/users}}
</ul>
Contain your logic in View classes, and leave your Mustache templates logic-less. UI code that is separated this way makes it so much easier to maintain and re-factor later on.

PHP - Solving problems with Closures and Reflection

I needed to create dynamic breadCrumbs that must be realized automatically by the application. So I have the following structure in the URL for navagation:
nav=user.listPMs.readPM&args=5
then i could have a function-file whose sole purpose would be to define the user.listPMs.readPM function itself:
file: nav/user.listPMs.readPM.php
function readPM($msgId)
{
/*code here*/
}
Of course this ends up cluttering the global scope since i'm not wrapping the function withing a class or using namespaces. The best solution here seems to be namespacing it, no doubt right? But I also thought of another one:
file: nav/user.listPMs.readPM.php
return function($msgId)
{
/*code here*/
};
Yep, that simple, the file is simply returning an anonymous function. I think this is amazing because i don't need to care about naming it - since i've already properly named the file that contains it, creating a user function and yet having to name it would seem just redundant. Then in the index I would have this little dirty trick:
file: index.php
if($closure = #(include 'nav/'.$_GET['nav']))
{
if($closure instanceof Closure)
{
$obj = new ReflectionFunction($closure);
$args = explode(',',#$_GET['args']);
if($obj->getNumberOfParameters($obj)<=count($args))
call_user_func_array($closure,$args);
else
die('Arguments not matching or something...');
} else {
die('Bad call or something...');
}
} else {
die('Bad request etc.');
}
Don't even need to mention that the breadCrumbs can be nicely built latter just by parsing the value within the $_GET['nav'] variable.
So, what do you think, is there a better solution to this problem? Have you found another way to explore Closures and/or Reflection?
I like the basic idea. But the implementation is pretty much terrible. Imagine that I set nav=../../../../../../etc/passwd. That would (depending on your server configuration) allow me to access your password file, which certainly is no good.

Symfony Model Callback Equivalent

I'm working on a Symfony project (my first) where I have to retrieve, from my Widget class, a set of widgets that belong to a Page. Before returning the results, though, I need to verify--against an external service--that the user is authorized to view each widget. If not, of course, I need to remove the widget from the result set.
Using CakePHP or Rails, I'd use callbacks, but I haven't found anything similar for Symfony. I see events, but those seem more relevant to controllers/actions if I'm reading things correctly (which is always up for discussion). My fallback solution is to override the various retrieval methods in the WidgetPeer class, divert them through a custom method that does the authorization and modifies the result set appropriately. That feels like massive overkill, though, since I'd have to override every selection method to ensure that authorization was done without future developers having to think about it.
It looks like behaviors could be useful for this (especially since it's conceivable that I might need to authorize other class instances in the future), but I can't find any decent documentation on them to make a qualified evaluation.
Am I missing something? It seems like there must be a better way, but I haven't found it.
First of all, I think behavior-based approach is wrong, since it increases model layer coupling level.
There's sfEventDispatcher::filter() method which allows you to, respectively, filter parameters passed to it.
So, draft code will look like:
<somewhere>/actions.class.php
public function executeBlabla(sfWebRequest $request)
{
//...skip...
$widgets = WidgetPeer::getWidgetsYouNeedTo();
$widgets = $this->getEventDispatcher()->filter(new sfEvent($this, 'widgets.filter'), $widgets));
//...skip...
}
apps/<appname>/config/<appname>Configuration.class.php
//...skip...
public function configure()
{
$this->registerHandlers();
}
public function registerHandlers()
{
$this->getEventDispatcher()->connect('widgets.filter', array('WidgetFilter', 'filter'));
}
//...skip
lib/utility/WidgetFilter.class.php
class WidgetFilter
{
public static function filter(sfEvent $evt, $value)
{
$result = array();
foreach ($value as $v)
{
if (!Something::isWrong($v))
{
$result[] = $v;
}
}
}
}
Hope you got an idea.
Here's some documentation on Symfony 1.2 Propel behaviors: http://www.symfony-project.org/cookbook/1_2/en/behaviors.
Why not just have a 'getAllowedWidgets' method on your Page object that does the checks you're looking for? Something like:
public function getAllowedWidgets($criteria = null, PropelPDO $con = null) {
$widgets = $this->getWidgets($criteria, $con);
$allowed = array();
// get access rights from remote service
foreach($widgets as $widget) {
// widget allowed?
$allowed[] = $widget;
}
return $allowed;
}
However, if you always want this check to be performed when selecting a Page's Widgets then Propel's behaviours are your best bet.
Although, at least in theory, I still think that a behavior is the right approach, I can't find a sufficient level of documentation about their implementation in Symfony 1.4.x to give me a warm and fuzzy that it can be accomplished without a lot of heartburn, if at all. Even looking at Propel's own documentation for behaviors, I see no pre- or post-retrieval hook on which to trigger the action I need to take.
As a result, I took my fallback path. After some source code sifting, though, I realized that it wasn't quite as laborious as I'd first thought. Every retrieval method goes through the BasePeer model's doSelect() method, so I just overrode that one in the customizable Peer model:
static public function doSelect( Criteria $criteria, PropelPDO $con = null ) {
$all_widgets = parent::doSelect( $criteria, $con );
$widgets = array();
foreach ( $widgets as $i => $widget ) {
#if( authorized ) {
# array_push( $widgets, $widget );
#}
}
return $widgets;
}
I haven't wired up the service call for authorization yet, but this appears to work as expected for modifying result sets. When and if I have to provide authorization for additional model instances, I'll have to revisit behaviors to remain DRY, but it looks like this will suffice nicely until then.

Categories