I can see how you would like that better, however I would rather type $this->kernel->blah than create tons of individual functions for every class or common task. I'm a very fast typer so it really doesn't bother me too much. Besides, it's less typing that having to create new instances of each class all over the place.Mordred wrote:So, basically you've invented global functions with lots of -> thrown in.astions wrote:Yeah either way. You just need to get an instance of it over the other class somehow. In my framework I use a kernel that in addition to a number of other things, holds an object of every class. So I can call any method of any class from any place and it saves a ton of memory PLUS it's very quick.
I'm all for the global functions to access "kernel" functionality, but I hate typing useless syntax sugar around, just because PHP doesn't have any reasonable scope modifiers (and no, 'global' is not reasonable).
For example instead of $this->kernel->db->query("blah") I do DBQuery("blah"), you do the math on how much typing it saves and how much readability it adds. I do have a DB object that I can pass around should I ever want to use two DB connections simultaneously, but I've yet to come to this need. Instead, with this wrapper of the "default" db connection, I cover 99.999% of use cases with significantly less typing and maintenance code. I would not bear to type a hundred -> which will always have the same object on the left.
Accessing class instances
Moderator: General Moderators
Accessing class instances
This is split from: viewtopic.php?f=19&t=83441 so we don't hijack onions thread.
Re: Accessing class instances
Ah, but you do create tons of functions, only in the form of methods. If only would PHP allow us to define superglobals, I would happily write $g_db->Query("foo") or $g_Log->Log("bar"). Alas, the only superglobal thing in our control is defining functions.
Don't get me wrong, I think your method is the next best thing (or the prev best thing?
), I use something similar in one or two cases. The point is, there are things, global in nature, that PHP would not allow us to handle easily, so we have to work around the limitation:
1. Use 'global'
2. Use registries, etc. (your method is essentially this, only in a nicer wrapping)
3. Use members, passed to the object at construct time
4. Use functions
Deffects:
1: Cumbersome to use, fails invisibly (i.e. with delayed effect) if we forget the global. Major no-no.
2: The problem is ofset to only one object - the registry, kernel, etc.
3: Treating globals like members. Could be a positive effect in unit testing, and nowhere else (is this correct?)
4: Possible namespace clashes
2 also has this workaround: the thing which you do with "kernel" and I do with my "response" object is to assign it to a member by reference in the constructor, and access it as $this->kernel->foo. Only one place to use a 'global', and the $this->, while a bit awkward to type is bearable.
All of these (except arguably 3) are not the best solution, I would prefer that PHP had:
- user-defined superglobals (what the other languages define as 'global')
- Namespaces
Then 1, 2 and 4 would had 'proper' and easy ways to use, and 3 would be the alternative if you wanted unit testing.
The reason I prefer 4, is that I don't do unit testing - there's little in web coding that could use some IMO, mostly related libraries like Swift or HTMLPurifier. Oh, how did I want to be able to unit test some of my projects, I had to write custom debugging solutions for a proxy server, because you had to be able to test and examine it while it is active. In the end I wrote a second server in the same process, that I connected to with telnet and which would interpret commands to examine the internals of the proxy. (Yeah, I know, uphill both ways in the snow, etc...)
Don't get me wrong, I think your method is the next best thing (or the prev best thing?
1. Use 'global'
2. Use registries, etc. (your method is essentially this, only in a nicer wrapping)
3. Use members, passed to the object at construct time
4. Use functions
Deffects:
1: Cumbersome to use, fails invisibly (i.e. with delayed effect) if we forget the global. Major no-no.
2: The problem is ofset to only one object - the registry, kernel, etc.
3: Treating globals like members. Could be a positive effect in unit testing, and nowhere else (is this correct?)
4: Possible namespace clashes
2 also has this workaround: the thing which you do with "kernel" and I do with my "response" object is to assign it to a member by reference in the constructor, and access it as $this->kernel->foo. Only one place to use a 'global', and the $this->, while a bit awkward to type is bearable.
All of these (except arguably 3) are not the best solution, I would prefer that PHP had:
- user-defined superglobals (what the other languages define as 'global')
- Namespaces
Then 1, 2 and 4 would had 'proper' and easy ways to use, and 3 would be the alternative if you wanted unit testing.
The reason I prefer 4, is that I don't do unit testing - there's little in web coding that could use some IMO, mostly related libraries like Swift or HTMLPurifier. Oh, how did I want to be able to unit test some of my projects, I had to write custom debugging solutions for a proxy server, because you had to be able to test and examine it while it is active. In the end I wrote a second server in the same process, that I connected to with telnet and which would interpret commands to examine the internals of the proxy. (Yeah, I know, uphill both ways in the snow, etc...)
Re: Accessing class instances
I think I understand what your saying. Let me tell you where I am at and then I will respond.
See this line:
I think I'm about as lazy as any other programmer. My goal is to write the least amount of code to do the most amount of work. Your right that the functions are there, but they are organized into classes. This is what that line does in my framework.
1. If the database class doesn't exist it is autoloaded (ie the file containing it is located and included) and instantiated
2. Depending on the configuration, it will either load a mysql or mysqli version of the database class
3. If their is no database connection, a database connection is established
4. The turbo_row method is called
5. If the query fails or no records are returned false is returned
6. The first record is placed into a variable and returned, which is then assigned to the $record variable
7. The mysql result is freed
8. If $record === false an exception is thrown.
I automate a lot of common tasks from within my framework, which is something I wouldn't be able to do with functions, unless each function explicitly performed a specific task.
This line does the same thing, except it will get 50 article titles from starting from page 1 and return the total results, total number of pages etc, all with a single database call and single line of code.
Now don't get me wrong, if I could make $_KERNEL a superglobal I would, but the way I lay things out I don't need to. The $_KERNEL variable is available everywhere it is needed automatically. To save typing I could change it to $_k or something but I'm not too concerned as it's already saving me loads of typing.
If there was a way to capture undefined function calls before php throws a fatal error I could probably do some neat stuff with that, such as create the function on the fly based on some sort of naming convention.
I think in the end user defined superglobals would come in handy for experienced programmers, but for beginners it would be a major step backwards. I once saw a CMS system where the guy who wrote it used $_SESSION for EVERY single variable, and yes, some very difficult to diagnose bugs cropped up. In the end I rewrote it from scratch.
As far as unit testing goes, I don't unit test at all. I learned PHP at a young enough age that I feel like it's a second language. I can read code and I do a pretty good job at processing it in my head as I'm reading it. There are unique situations however. Last week I wrote a bitmapper class, which probably isn't over 15 lines of code that I wrote tests for and tested for about 5 hours. I tested a variety of input, took it and put it in the database, pulled it back out and made sure everything came back out ok. This lead me to find an issue with number_format that I posted here the other day.
Going back to my framework however, one thing that used to drive me nuts with other frameworks is that I would see new classname() every where. Even nested, new classname(new plugin()). These frameworks were slow and used tons of memory. I think even PHPBB needs something like 8mb of memory or something? With my framework nothing is loaded (included) unless and until it's needed, it won't even connect to the database until the first query is executed. No query = No need to connect. Classes are reused and there really isn't bloat. I just can't do this with functions.
See this line:
Code: Select all
if (false === ($record = $_KERNEL->db->turbo_row("select user_id from auth where username = 'sample' and MD5('password') = 'test'")))
{
throw new Exception('Invalid username or password');
}
1. If the database class doesn't exist it is autoloaded (ie the file containing it is located and included) and instantiated
2. Depending on the configuration, it will either load a mysql or mysqli version of the database class
3. If their is no database connection, a database connection is established
4. The turbo_row method is called
5. If the query fails or no records are returned false is returned
6. The first record is placed into a variable and returned, which is then assigned to the $record variable
7. The mysql result is freed
8. If $record === false an exception is thrown.
I automate a lot of common tasks from within my framework, which is something I wouldn't be able to do with functions, unless each function explicitly performed a specific task.
This line does the same thing, except it will get 50 article titles from starting from page 1 and return the total results, total number of pages etc, all with a single database call and single line of code.
Code: Select all
if (false === ($records = $_KERNEL->pagination->get_page("select article_title from articles", 1, 50)))
{
throw new Exception('There are no articles to display.');
}
If there was a way to capture undefined function calls before php throws a fatal error I could probably do some neat stuff with that, such as create the function on the fly based on some sort of naming convention.
I think in the end user defined superglobals would come in handy for experienced programmers, but for beginners it would be a major step backwards. I once saw a CMS system where the guy who wrote it used $_SESSION for EVERY single variable, and yes, some very difficult to diagnose bugs cropped up. In the end I rewrote it from scratch.
As far as unit testing goes, I don't unit test at all. I learned PHP at a young enough age that I feel like it's a second language. I can read code and I do a pretty good job at processing it in my head as I'm reading it. There are unique situations however. Last week I wrote a bitmapper class, which probably isn't over 15 lines of code that I wrote tests for and tested for about 5 hours. I tested a variety of input, took it and put it in the database, pulled it back out and made sure everything came back out ok. This lead me to find an issue with number_format that I posted here the other day.
Going back to my framework however, one thing that used to drive me nuts with other frameworks is that I would see new classname() every where. Even nested, new classname(new plugin()). These frameworks were slow and used tons of memory. I think even PHPBB needs something like 8mb of memory or something? With my framework nothing is loaded (included) unless and until it's needed, it won't even connect to the database until the first query is executed. No query = No need to connect. Classes are reused and there really isn't bloat. I just can't do this with functions.
- John Cartwright
- Site Admin
- Posts: 11470
- Joined: Tue Dec 23, 2003 2:10 am
- Location: Toronto
- Contact:
Re: Accessing class instances
So you are suggesting that creating objects, and passing objects to other objects is bad practice? Small, compact, concise, testable, and loosely coupled are what makes excellent code -- not the other way aroundGoing back to my framework however, one thing that used to drive me nuts with other frameworks is that I would see new classname() every where. Even nested, new classname(new plugin()).
I would not use phpBB or phpBB2 as examples of well written code. It's a procedural mess, and it's memory usage is a joke. Although, their bottlenecks do not come from their usage of OOP though.These frameworks were slow and used tons of memory. I think even PHPBB needs something like 8mb of memory or something?
Mine tooWith my framework nothing is loaded (included) unless and until it's needed, it won't even connect to the database until the first query is executed. No query = No need to connect. Classes are reused and there really isn't bloat. I just can't do this with functions.
Re: Accessing class instances
No not at all. I'm saying that creating 5 instances of 10 classes all over the place (50 instantiated classes) is bad practice. Sure the code might be organized, there's nothing wrong with that. The problem for me lies in the efficiency. I've found a way to keep my code organized while maintaining a high level of efficiency (cpu & ram) and increased productivity. I disagree that I am arguing against OOP. I believe I am arguing against a style of OOP which happens to be mainstream.Jcart wrote:So you are suggesting that creating objects, and passing objects to other objects is bad practice? Small, compact, concise, testable, and loosely coupled are what makes excellent code -- not the other way around. You are basically arguing against PHP being used in an OOP context, which is not an argument at all, but if you want to argue that procedural code will be faster than OOP code then sure (but you are losing many benefits).
EDIT: I'm not sure you read what I wrote. I'm not the one advocating functions here.
Re: Accessing class instances
Efficiency is having the luxury to optimize comfortably when needed. Maintainability is a far more common need than optimization, and leads to much easier optimization when the need arises.
Re: Accessing class instances
I'm having my cake and eating it too. Nom Nom Nom.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Accessing class instances
You actually mean, "... in my opinion." The thing about a solo programmer building a code base is that you certainly believe in your code, but there is no reality as to whether you could be more efficient or productive. There is a saying:astions wrote:I've found a way to keep my code organized while maintaining a high level of efficiency (cpu & ram) and increased productivity.
"Infinite intellectual brilliance is achieved as the size of the audience approaches zero."
Working on a framework with others (and trying to get my head around all of the new and interesting ideas that other programmers have) has show me repeatedly that my designs are not always so efficient or productive. And I think my design sense is pretty good!
(#10850)
Re: Accessing class instances
Well that's a way to look at it. I think that you can't prove and I cannot disprove that theory. I certainly do believe in my code, but I don't think that I think it's better than anything else just because I wrote it. We are getting a bit off topic though. Mordred and I were discussing functions vs a centralized method of storing class objects.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Accessing class instances
Yeah ... I read that. I really don't see the functional difference between your $_KERNEL-> and the $this-> Helpers and or registry of an Action Controller. I do see a number of other differences though ...
(#10850)
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
Re: Accessing class instances
phpBB needs a lot more than 8MBThese frameworks were slow and used tons of memory. I think even PHPBB needs something like 8mb of memory or something?
Re: Accessing class instances
Yeah there is a fine line there. I generally stay on the right side of it. At least I try to.
Re: Accessing class instances
Hey Mordred, why not just create some get & set functions that pull variables from a static class. Something like:
That'd be an easy way to have global vars.
Code: Select all
function get($var)
{
static $ram = ram::getInstance();
return $ram->get_variable($var);
}
function set($var, $value)
{
static $ram = ram::getInstance();
return $ram->set_variable($var, $value);
}
Re: Accessing class instances
I don't want just any var to be easily accessible as a global, I want those that are global in nature, which are really just a handful, but are used all the time.
That's why I propose something very similar to this, but in a more limited way. Your example above is a registry with global access functions. But we actually want to get only several things out of it. So, instead of accessing a global registry and get a global var from it - access the var directly! Have a set of functions for database, a set for logging, a set for profiling, aaand that's about it. If you want another, have another set. I actually only do it for the database and the profiler (which I don't really use anymore).
Here's a real example from my database class (I purposely cose the simplest function, so not do distract the reader from the topic of global access to the database class intrinsics):
You use it by just calling
What helps us keep the code short here is allowing the assumption that we only have one database connection - which is true almost always. The same applies to doing logging, profiling, etc.
That's why I propose something very similar to this, but in a more limited way. Your example above is a registry with global access functions. But we actually want to get only several things out of it. So, instead of accessing a global registry and get a global var from it - access the var directly! Have a set of functions for database, a set for logging, a set for profiling, aaand that's about it. If you want another, have another set. I actually only do it for the database and the profiler (which I don't really use anymore).
Here's a real example from my database class (I purposely cose the simplest function, so not do distract the reader from the topic of global access to the database class intrinsics):
Code: Select all
//We have a class:
class CMysqlDatabase {
//...
function GetAffectedRows() {
return mysql_affected_rows($this->m_connection);
}
//...
};
//A global variable:
$g_pDatabase =& new CMysqlDatabase(); //supposing we want MySQL
//And an accessor function:
function DBGetAffectedRows() {
global $g_pDatabase;
return $g_pDatabase->GetAffectedRows();
}Code: Select all
$nRows = DBGetAffectedRows();- superdezign
- DevNet Master
- Posts: 4135
- Joined: Sat Jan 20, 2007 11:06 pm
Re: Accessing class instances
But in the concepts that OOP was built on, objects are created and the only objects with access to them are the ones that need access. It's the whole issue of "uses" and "has." If an object only outputs HTML, and it doesn't use the database to do that, then the object should not have access. Also, the objects that do have access won't be easily identified from the objects that don't, as any object can simply add that call.
Using include() for the necessary classes is considered better practice than the autoload capability created by PHP. Also, relying on a superglobal assumes that it has had a chance to be created. $_SESSION doesn't exist until session_start() is called. Building code which relies on another piece of code being run beforehand means that the code in question will need to do a check to make sure that the needed code has been run, which is an unnecessary overhead than running include_once().
Using include() for the necessary classes is considered better practice than the autoload capability created by PHP. Also, relying on a superglobal assumes that it has had a chance to be created. $_SESSION doesn't exist until session_start() is called. Building code which relies on another piece of code being run beforehand means that the code in question will need to do a check to make sure that the needed code has been run, which is an unnecessary overhead than running include_once().