PDA

View Full Version : [WIP] Studio: Greeble



Rob Oplawar
February 6th, 2009, 11:25 PM
Hi guys. I'm going to try to semi-regularly post the source code of Greeble as I finish it, up until the alpha release of Greeble when the timer at http://greeble.net expires.

This code is open-source, and is meant to be self-documenting, meaning you can just grab any old source code file out of Greeble and look at it by itself and figure out mostly how it works, no searching around for external documentation or guessing at what an included file or referenced function does.
The comments at first glance appear extremely verbose, to the point of cluttering the code-- it's meant to be viewed in a modern editor, and most modern editors will automatically collapse large comment blocks like that into one line, making the code much more readable.
The @ prefixes on certain lines in the comments indicate the comment line's special meaning to an editor, usually to give it information on a class method to help the programmer when calling said method.
The @access annotations are redundant and I really ought to go ahead and remove those, but they're friggin everywhere. Lol.


First off, the second most useful class I have ever written:
MySQLRow (http://greeble.net/MySQLRow.txt).

Next week: the most useful class I have ever written, MySQLTreeRow!

Masterz1337
February 6th, 2009, 11:37 PM
Sweet Deal.

SnaFuBAR
February 7th, 2009, 12:43 AM
Still want me to try that logo for you, Rob?

Rob Oplawar
February 7th, 2009, 01:22 PM
Yes please.

So, I just added the MySQLRowFactory class yesterday. Before all of that functionality was part of MySQLRow. As a result of this new way of doing things, my classes that extend MySQLRow (about 10 of them) have decreased in size by about 100 lines each.

A sign of huge progress- my framework just got 1000 lines smaller overnight. :)

MySQLTreeRow on the way, as soon as I work out all the bugs so my unit tests pass.

e: Updated MySQLRow (http://greeble.net/MySQLRow.txt) to make it more flexible.

Advancebo
February 7th, 2009, 07:16 PM
Whats a Greeble :V?

Limited
February 7th, 2009, 07:39 PM
Whats a Greeble :V?
His PHP based forums he made from scratch.

Nice rob work, huge count timer, 21 days? :P

Rob Oplawar
February 15th, 2009, 03:36 PM
Ok, still working on MySQLTreeRow.

In the meantime, I've renamed MySQLRow.php to DBRow.php, to reflect the fact that I've now added a layer of abstraction to it, so that the interface can be database independent. Currently I've only implemented it for MySQL and have no plans to implement for any other databases, but it's good to leave your code open to modification.

I've also changed around the code somewhat in anticipation of PHP 5.3.0, which supports late static binding, which will be a huge code-saver for me.

I got rid of the MySQLRowFactory class, bringing that functionality back into MySQLRow, and am just living with the fact that until late static binding is supported I will have about 50 lines of duplicate code per class that extends DBRow, and will have numeruous call_user_funcs in there, in addition to having a slightly wonked out interface.
5.3.0 comes out sometime this quarter, so hopefully I won't have to live with this for long.


I've also finished writing the unit tests for the DBRow class. 23 tests, 145 assertions, all pass. It doesn't provide quite 100% coverage, so in the future I may want to make those tests a bit more thorough just to be sure, but in the meantime it shows that the code is solid for general use.


The coolest part of the MySQLRow class is, in my opinion, its support for SQL JOINs. The interface has two types of joins- tableJoin and classJoin.
Table join works exactly like a normal SQL join, with a couple of restrictions. It performs an inner join from the primary table of the class it belongs to to some other table on the my_index field. This is for relational support, splitting a table into multiple tables to lighten queries when not all columns are necessary.
In the future I plan to remove the restriction to INNER joins on my_index, to be more flexible.
The other join, Class Join, does one better. It can perform LEFT, INNER, or RIGHT join from one DBRow class to another DBRow class. It's hard to describe how it works in the abstract, so have an example instead: Say I have a posts table and a users table in a forum system, and matching Post and User classes. I can left classJoin Post to User on post.author_index = user.my_index, and then when I get post 1 from the database with $post = new Post(1), it will magically have a User object attached to it, accessible with $post->getJoinedClass(User), where the User object is the user who authored the post.
This also works with fetching a group of objects: $posts = Post::fetchs('`parent_index`=1'); $posts will be an array of Post objects, and each Post will have an attached User.
In the future I will tie this in to the caching support, so that if multiple posts have the same author, the Post objects will all have references to the same User object.

e: The reason this is cool is because it does it all with one query. I've found that the time spent communicating between the database server and the php server is generally the biggest code bottleneck, so my optimization focuses on reducing the number of queries as much as possible. This is a trade-off; this code takes fewer queries, but it takes just a little bit more processor time to execute the extra logic. So, it might possibly be slower when the processor is being completely used by scripts, but in that case I expect the communication bottleneck would narrow as well making this code ultimately faster.


So, without further ado, here they are:

DBRow.php (http://greeble.net/DBRow.txt)
DBRowTest.php (http://greeble.net/DBRowTest.txt)

Rob Oplawar
February 28th, 2009, 02:46 PM
The longer I work on Greeble, the more PHP bugs I uncover. Here's the latest bug I've found (it's fixed in the latest build of php, but not in the latest release of php, which is what I'm using) (it's Windows only; the identical code runs fine on my Linux box):


<?php
class A {
static function b($classname) {
//the following two lines run fine:
$x = c();
call_user_func(d, $x);

//as does this line:
d(c());

//this line, however, causes apache to crash. Lovely, eh?
call_user_func(d, c());
}
}

class B extends A{
public static function a() {
parent::b(B);
}
}

function c() {
debug_backtrace();
}
function d($x) {}

B::a(1);
?>

Took me a while to boil it down to its essential components. It requires class inheritance, function overriding, call_user_func, and evaluation of a function in the context of an argument to another function. The crash happens on debug_backtrace().

My suspicion is that there's some sort of infinite loop occuring in debug_backtrace causing a stack overflow.


The bright side is that I can workaround this problem as shown in the two pieces above the disastrous call_user_func, and that the only reason I have a call_user_func in the first place is a workaround for the absence of late static binding in the latest release of php, which won't be necessary much longer.

Rob Oplawar
March 1st, 2009, 11:42 AM
Final bump/doublepost:
greeble.net is now live:
http://greeble.net/web/logo_large.png (http://greeble.net)

klange
March 1st, 2009, 08:11 PM
All your theme are belong to me. (http://ogunderground.com)

Thanks for letting me port your site theme. I demand you get that forum working ASAP.

SnaFuBAR
March 1st, 2009, 09:08 PM
imo that's pretty cheap of you, Abacon. have you no individuality?

klange
March 1st, 2009, 09:57 PM
imo that's pretty cheap of you, Abacon. have you no individuality?
Four hours of collaborative work is "cheap" of me?

Rob Oplawar
March 1st, 2009, 10:38 PM
Snaf, you're missing out on the spirit of open source. I want people to use and build on the work I've done.

Rob Oplawar
March 17th, 2009, 03:55 PM
Bump.

I want to discuss a certain aspect of my framework with anyone experienced in PHP.

The Article module is relatively simple compared to some of my other planned modules, and yet its execution time is starting to get up there. To view an article, 20 separate PHP files need to be loaded and parsed.

Here is a tree structure representing the files that are loaded, how long they took to load, and which files loaded them in the first place.



120ms: index.php
8ms: Control/framework.php
0ms: Control/config.php
1ms: MySQLiSession.php
0ms: framework language file: en-US
106ms: Article renderer
4ms: Article/Control/Scripts.php
3ms: Article language file: en-US
15ms: Article/Model/Article.php
0ms: Article/Control/config.php
5ms: DBRow.php
4ms: DBTreeRow.php
2ms: User/Model/User.php
0ms: User/Control/config.php
0ms: User language file: en-US
3ms: Article/Model/ArticleCategory.php
1ms: HTML.php
1ms: User/View/Templates.php
3ms: Article/View/Templates.php
4ms: Form.php


To put it in more readable english,


the initial view script (the page requested by the client browser) loads:
Greeble framework, which loads:
framework configuration
MySQL session handler
framework language file
Article renderer, which loads:
Article control scripts (a bunch of logic, input validation, etc), which loads
Article language file
Article Class Definition, which loads
Article configuration file
Database abstraction class
Database tree structure abstraction class
User class definition, which loads
User configuration file
User Language file
Article Category class definition
base HTML templating class
User templating class
Article templating class
Form templating class


Obviously, in this example, the article render script is the biggest timesuck by far. The files it depends on take a total of 36 milliseconds to execute (and that execution time is basically just the time it takes to compile, as all those files just contain class/function/constant definitions), so on its own it's spending 70 milliseconds doing its thing.

Keep in mind this is running on my windows machine with Firefox, AIM, iTunes, and Eclipse running in addition to Apache with PHP, which are all notorious memory hogs. It runs on average about twice as fast on my linux laptop, and considerably faster on my production server.



So, I dunno, I guess I'm asking what your impressions are of this.
My first impression is "gosh, Greeble's getting kind of bloated... :("