I'm trying to find the best pragmatic approach to import functions on the fly... let me explain.
Say I have a directory called functions which has these files:
array_select.func.php
stat_mediam.func.php
stat_mean.func.php
.....
I would like to: load each individual file (which has a function defined inside) and use it just like an internal php function.. such as array_pop(), array_shift(), etc.
Once I stumbled on a tutorial (which I can't find again now) that compiled user defined functions as part of a PHP installation.. Although that's not a very good solution because on shared/reseller hosting you can't recompile the PHP installation.
I don't want to have conflicts with future versions of PHP / other extensions, i.e. if a function named X by me, is suddenly part of the internal php functions (even though it might not have the same functionality per se) I don't want PHP to throw a fatal error because of this and fail miserably.
So the best method that I can think of is to check if a function is defined, using function_exists(), if so throw a notice so that it's easy to track in the log files, otherwise define the function. However that will probably translate to having a lot of include/require statement in other files where I need such a function, which I don't really like. Or possibly, read the directory and loop over each *.func.php file and include_once. Though I find this a bit ugly.
The question is, have you ever stumbled upon some source code which handled such a case? How was it implemented? Did you ever do something similar? I need as much ideas as possible! :)
One way you could pull something like this off is to put those functions into classes and then set up an __autoload function. If you are against wrapping the functions in classes than this solution probably won't apply to you. Personally I like it because it allows me to namespace my functions and share private methods between them.
First you set up your autoload function similar to this. You'll want to adjust the naming convention to fit your own style, and probably introduce some error handling, but this is just to get the basic idea across.
function __autoload($class_name){
require_once(strtolower("library/$class_name.class.php"));
}
Then anywhere in your code regardless of scope you can do something like this.
arrayFunctions::doStuff($myArray);
PHP will automatically try to include "library/arrayFunctions.class.php" and look for a method called "doStuff" in the arrayFunctions class.
I have issues with this idea. Hitting the file system to include a single function is very expensive in the terms of it lowering your max possible requests per second.
It's generally much better to load/parse five functions in a single file (static class?) and only use two of them (one stat call) rather than load two files for two functions (two stat calls).
Which obviously becomes even worse when you need all five functions.
To automatically load stuff when need, put your functions in classes and use autoloading.
For the name conflict, use namespaces (if you have PHP 5.3).
Related
I designed a PHP 5.5+ framework comprised of more than 750 different classes to make both web applications and websites.
I would like to, ideally, be able to reduce its size by producing a version of itself containing just the bare essential files and resources needed for a given project (whether it's a website or a web application).
What I want to do is to be able to:
reduce the amount of traits, classes, constants and functions to the bare essential per project
compress the code files to achieve a lesser deployment size and faster execution (if possible)
So far, I've got the second part completed. But the most important part is the first, and that's where I'm having problems. I have a function making use of get_declared_classes() and get_declared_traits(), get_defined_constants() and get_defined_functions() to get the full list of user-defined classes, traits, functions and constants. But it gives me pretty much EVERYTHING and that's not what I want.
Is there a way to get all defined classes, functions and constants (no need for traits as I could run class_uses() on every class and get the list of traits in use by that class) for a single given script?
I know there's the token_get_all() function but I tried it with no luck (or maybe it's I'm using it the wrong way).
Any hint? Any help would be greatly appreciated :)
You can use PHP Parser for this. It constructs abstract syntax trees based on the files you supply to it. Then you can analyze its output for each file, and produce a report usable to you.
Other than that, you can use token_get_all() approach you've mentioned already, and write a small parser yourself. Depending on your project, this might be easier or more difficult. For example, do you use a lot of new X() constructs, or do you tend to pass dependencies via constructors?
Unfortunately, these are about the only viable choices you have, since PHP is dynamically typed language.
If you use dependency injection, however, you might want to take a look at your DI framework's internal cache files, which often contain such dependency maps. If you don't use such framework, I recommend to start doing this, especially since your project is big and that's where dependency injection excels at. PHP-DI, one of such frameworks, proved to be successful in some of my middle-size projects (25k SLOC).
Who knows? Maybe refactoring your project to use DI will let you accomplish the task you want without even getting to know all the dependencies. One thing I'm sure of is that it will help you maintain it.
I have this problem that is really causing me headeches whenever i'm designing my apps in php: I don't know if i should create separete files for each function(e.g.: functions for validating specific forms).
OK, one would possibily argue that this makes no sense because I would have to include each file separetly and this would result in a more slow application maybe?
But I still think it does make sense since for one pageload i doubt that other functions would be used by the script at all, so they must be loaded just for nothing? besides, i don't have to include each function-file manually if the system i design does this dinamically (parsing url vars or such) for me, that is, loading function(-files) exactly when needed. What do you think?
The overhead in file includes is minimal, you shouldn't have to worry about it really, considering caching and other things. Of It's more about how you can keep yourself organized and find your stuff quickly.
Honestly, I rarely use functions, I use classes. The rule is usually to have a class per file. But I also have a toolbox file that contains all my global functions.
Are you using OO? If so, then you should definitely keep it one class per file, and name the files intelligently...
class Page {
...
}
should be findable somewhere like classes/Page.php or includes/Page.class.php or similar.
If you just have a bunch of global functions, you should group them in files, e.g. includes/functions/general.php.
To elaborate, your functions folder may have...
array.php
string.php
form_validation.php
request.php
general.php
html.php
If you are organising your files like this, a better idea is to use a class and make the functions static, e.g. string::isAlphaNum($str). This is a better idea because it only introduces one new term to your global namespace, instead of a bunch of them needlessly.
If you are using PHP 5.3, you could also look at namespaces.
You should just make sure that you have APC, xCache or eAccelerator installed. All of them provide cache for compiled PHP bytecode.
It means that once the file has been included it will be stored in memory and ready to use by feature requests. There won't be any need to include files.
You will almost certainly see a more significant performance hit through increased disk I/O reads on (many) multiple file includes than for smaller set of files with many functions.
For automatic file includes, wrap functions into suitable classes and use spl_autoload to let PHP handle the include process.
I'd like to check if my understanding's correct about require_once(). I have a bunch of functions in file foo.php. Let's say 7/8 out of them are always used, and one of them's rather rare and rather large. I have to keep this function's definition in foo.php. Can you tell me if the following approach achieves anything, and if you think it's worth what it achieves.
Take out the body of the function and put it in an external file.
Redefine the original function to require_once() that particular file and pass execution over to the helper function.
I understand this could save server memory on the requests where that function isn't run. What exactly am I saving though? Just the memory it takes to hold the body of the function? That would mean it would have to be a pretty big function before being worth it I guess. Also, if I'm using something like APC does it become less useful?
Please correct or add to this as appropriate!
Thank you very much.
I highly doubt you will gain anything from refactoring it into a separate file. Also, do you actually have any problems with the code as it is now that makes you consider this? You know premature optimization is the root of all evil. Profile your code to see if and where it has bottlenecks before you waste your time on pointless µoptimizations.
Update: From your comment to Gordon I see you're using Drupal: This method doesn't work there, because Drupal is heavily object-oriented already. What is described here is making use of the Autoloading mechanism for a function-based project using static classes.
As Gordon says, this will save memory only for really incredibly huge functions. In my experience, though, loading includes into memory takes up much more space than the exact number of bytes needed to hold the code. I'm not a PHP internals expert, but I assume the code is parsed or at least preprocessed either way.
Assuming your PHP application is entirely function-based with no OOP, one idea that comes to mind that you could use to split up your includes is putting your functions into classes, and making use of the autoloader mechanism:
class maintenance_functions
{
public static function xyz() { ................ }
and start calling them statically:
maintenance_functions::xyz();
one class would occupy one file.
Group all the rarely used functions into separate files.
Then, you could make use of the Autoloading mechanism. This will load needed classes automatically at the point they are needed. If I for example, call
datamining_functions::xyz();
the autoloader will look for the file containing datamining_functions and include that. This eliminates the complete 'require()' hassle and lets you concentrate on how to group your functions most efficiently.
This is not a real transition to OOP: We just use class constructs to group the functions, in order to be able to use the autoloader. It should be possible to migrate functions into such classes without the need for major rewrites.
You should use Xdebug to find out the answer - worth or not is subjective.
I use the following procedure to call the functions within the pages of my web app.
//index.php
include("functions.php");
include("file1.php");
include("file2.php");
I have all my functions going into functions.php page. The content of this page may be over 5000+ lines of code and it contains all the functions used within the website. So loading 5000+ lines of code in all the pages of my website, even when it's not needed, seems like a lot of load. So my questions is:
How to load only functions that are needed and only on demand without having to create a separate functions page for each of my pages?
Please consider this example:
//functions.php contains functions f1 through 10
function f1()
{
//do something
}
function f1()
{
//do something
}
...(through)
function f10()
{
//do something
}
If index.php page makes use of only functions f1 and f2, how can I load only those 2 functions on that page, without having to load all the rest of the functions (f3 through f10)? Please note that my app. is using mysql database(if that helps).
Also maybe it's worth mentioning again that one idea that I already have is that I will need to create functions for each of my pages i.e, functions_index.php page for use in index.php page and likewise, create different function pages for the rest of the pages in my app. While at once this seems like a good idea, I may end up duplicating the same function(s) over and over and this can lead to heavy duplication. My sole aim is to keep the functions centrally accessible by all the pages, yet load the functions only on demand. Hope this is possible.
Thank you.
Note: Please note that all the code written is mainly done via functions and IS NOT OOPS based. So I would really appreciate any solutions that can be implemented without having to switch to using OOPS concepts. Thanks again.
If you switch to an OO design, you can create an autoload function (and register it with spl_autoload_register) to load classes on-demand.
Other than that, perform some profiling to see what the impact is of loading all your functions. Performance-wise, there might not be a significant impact relative to other aspects. There's a design-wise impact of having a monolithic file containing all the functions you may need, namely the danger of increased coupling. You decrease coupling by separating concerns.
first of all, load 5k lines of code is not that hard for php, but other than that, you should seriously think about splitting your single file into separate, easy to handle chunks and while you are at it you could even start coding in an oop way
There's no really clean way to get PHP to load certain functions in certain places without a tradeoff involving code duplication. For example, you could separate your functions into logical classes, and then load only the appropriate class for the appropriate section - but those classes can't overlap, or you'll end up duplicating code and defeat what you're trying to do in the first place (and there's certain stuff that will always overlap).
However, if you're concerned about loading the same 5000+ line file repeatedly all over the place, the real questions are:
1) Are you seeing actual degraded performance because of this? If not, why worry?
2) If you are, have you thought about using APC (Alternative PHP Cache)? That would cut out repeated parsing of that file, though it would still get executed each time.
Can you divide them into groups that make sense?
For instance:
Database Functions
File Management functions
= String functions
If so, it may work for you to do something like that and then include only the groups you want.
page 1:
include_once("functions/db.php");
include_once("functions/strings.php");
and page 2 could be:
include_once("functions/files.php");
include_once("functions/strings.php");
I did something similar like this once. I came up with a three-part solution, one or all of which might help.
First I separated out the functions I know I will always need and put them in a directory called core, with a function that automatically loads them all when the index is loaded.
Then I identified things I only need sometimes and separated them out by scope. So one particular group of tools within the app might need a particular group of functions which are not needed anywhere else, and they can all be loaded with that same function from above.
Then there are some big things that I will need in random places (Like mailer, oauth, key-value store, etc) and these have minimal wrapper functions within core which then load all the extra libraries that they need when the wrapper function is called.
How do you manage your php codes? Do you prefer functioning within one php file or including larger blocks of "raw code"?
Edit: In fact, my code is pretty nasty, as I don't use any namespaces and classes - only functions and including. I shall look the classes up ^^.
Use them as you need them.
I use include for chunks of big code doing processing, and functions for "utility" functions. Sometines i use includes within function also... it really depends on how clean you like your code.
Think that many includes means more fopen() from the PHP module, and those can slow doewn the whole script execution..so dont try and put too many includes though.
If you are using php classes, this will sort itself out. If you are not, then it's really hard to give an acceptable answer, except that you should learn to. All php code I've seen done either way without classes seems to become quickly messy.
I agree that OOP is the way to go. Large solid blocks of code are nightmare for maintenance. Definately not the way to go. You should split your code into small blocks that interact with each other and are easily maintanable on their own.
When I used to program in PHP I liked to group general utility functions in a common file to include in most of the pages, and group classes in dedicated files, to load them only when needed.
I typically use functions/classes for logic and includes for display. I end up with something like this in a controller...
case 'widgetlist':
$widgets = $DAO->getWidgets(); //get some query
include('view/showWidgets.php'); //assume a global $widgets variable
break;
I have found it easier to give an HTML/CSS designer an include rather than a function call which displays. The down side is that I rely on globals to pass variables to the include rather than arguments which are much safer.
I make classes in separate files, with the correct prefixes as namespace (until they are included at least). I also put functions as static methods in "static classes" for the namespace effect.
I use autoload to include the files so I don't have to write a hundred includes.
Save My_Example_Class as {lib}/My/Example/Class.php
The thing I'm working on has one included file at the top of every page that contains all the global functions and database setup stuff. It works as-is but I'm now moving the functions into separate files, because with everything in a big lump it's completely impractical to do any testing.
PHP has an __autoLoad () magic function that you can use to intercept class calls. If the class doesn't exist yet, you can setup some simple code to go and look for the proper class code to include. It will then continue to execute as normal.