OOP design question

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
The Phoenix
Forum Contributor
Posts: 294
Joined: Fri Oct 06, 2006 8:12 pm

OOP design question

Post by The Phoenix »

I am working on revamping and recoding a web-based (PHP/MySQL driven) game. In the game, we output text as a variable string.

As an example, you might want to output to the user the phrase "Click here to return to the main menu", so we have a language variable file which has:

Code: Select all

$l_return_main = "Click here to return to the main menu";
Then when we need to output it, we do:

Code: Select all

echo $l_return_main;
This "worked" for a while. But we've gotten up to around 1400 variables now, and its starting to have some overhead. A page with just 20 strings of text suddenly has 1400 variables(!)

We're pondering storing it in a database, but during that process, it occurs to me that maybe languages need to be an object. A language object, and then english would extend that. I think the language object would only have a getter and a setter (?)

Am I on the right track here, in terms of design, or am I just seeing an object because I'm tired of staring at 30k lines of procedural-only code?

Any discussion would be *deeply* appreciated.
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: OOP design question

Post by Benjamin »

Well I think any way you look at it the complexity increases exponentially.

That being the case it would be good to store strings in the database with corresponding tokens.

The content should have tokens and be *compiled* if you will into various language templates. In other words, cache a token free version for each language.

This would reduce overhead to virtually nothing.

Off the top of my head I suppose you could have tables for languages, tokens, and token values. Token values would store the token_id, language_id and token_value.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: OOP design question

Post by Christopher »

The Phoenix wrote:I am working on revamping and recoding a web-based (PHP/MySQL driven) game. In the game, we output text as a variable string.

As an example, you might want to output to the user the phrase "Click here to return to the main menu", so we have a language variable file which has:

Code: Select all

$l_return_main = "Click here to return to the main menu";
Then when we need to output it, we do:

Code: Select all

echo $l_return_main;
You might want to look at the I18N solutions from various frameworks and apps to get a survey of your options.
The Phoenix wrote:This "worked" for a while. But we've gotten up to around 1400 variables now, and its starting to have some overhead. A page with just 20 strings of text suddenly has 1400 variables(!)
What does "some overhead" mean? Do you have an actual performance problem directly attributable to this? Perhaps using APC, if you don't already, might be a better solution that recoding?
The Phoenix wrote:We're pondering storing it in a database, but during that process, it occurs to me that maybe languages need to be an object. A language object, and then english would extend that. I think the language object would only have a getter and a setter (?)

Am I on the right track here, in terms of design, or am I just seeing an object because I'm tired of staring at 30k lines of procedural-only code?
Not sure what "languages need to be an object" means. Obviously you want to abstract the language part so that you don't have code dealing with that spread throughout the game. There are a number of solutions to the problem of providing multi-language support -- each with different trade-offs.
(#10850)
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: OOP design question

Post by VladSun »

There are 10 types of people in this world, those who understand binary and those who don't
User avatar
The Phoenix
Forum Contributor
Posts: 294
Joined: Fri Oct 06, 2006 8:12 pm

Re: OOP design question

Post by The Phoenix »

Benjamin wrote:Well I think any way you look at it the complexity increases exponentially.

That being the case it would be good to store strings in the database with corresponding tokens.
We have been discussing "tagging" (adding tokens for variables), because some phrases are in fact used in multiple files. However, I think it might be 'cleaner' if we just avoid tags entirely, and simply do a direct call for the variable name itself ($l_return_main in the example). As an SQL stored item, it would be a table with just name/value. Then on pages that use the same tag/token, it just uses the same name.

What I'm trying to get at is whether the interface for accessing the language should be in the form of a variable, a function, or a class? My suspicion is that English is an extension of a Language object, and that I should be providing the interface that way. I'm just looking to others with more OOP experience to offer advice on whether I'm over-reaching a bit. :)
User avatar
The Phoenix
Forum Contributor
Posts: 294
Joined: Fri Oct 06, 2006 8:12 pm

Re: OOP design question

Post by The Phoenix »

Christopher wrote:What does "some overhead" mean? Do you have an actual performance problem directly attributable to this? Perhaps using APC, if you don't already, might be a better solution that recoding?
Fair question. We have bumped into pages where we are running out of memory, as a combination of many things on the page. The languages just seemed an easy target that could improve things on every page. Most impact for the least work kind of issue.

APC is definitely an improvement, and we already encourage its use by admins. Unfortunately, some don't have that choice, and we work to optimize the game to work even without it.

As to avoiding recoding, that isn't an option. It is incredibly outdated code (we've uncovered hacks that fix PHP issues from before 4.2, that are no longer valid, for example), and that still rely on a register_globals style auto-import. We want to improve the game to add features, but to do so, we simply have to recode large portions of it to get beyond the design restrictions of the past.

Since we're already recoding, I figured it was time to rethink key design decisions (like the language design).
Christopher wrote:
The Phoenix wrote:We're pondering storing it in a database, but during that process, it occurs to me that maybe languages need to be an object. A language object, and then english would extend that. I think the language object would only have a getter and a setter (?)

Am I on the right track here, in terms of design, or am I just seeing an object because I'm tired of staring at 30k lines of procedural-only code?
Not sure what "languages need to be an object" means. Obviously you want to abstract the language part so that you don't have code dealing with that spread throughout the game. There are a number of solutions to the problem of providing multi-language support -- each with different trade-offs.
Today, the "interface" for a programmer on the game wanting to get output that is translated to match the users desire is a variable. (That the variable is actually in the global scope is just insult to injury). I'm trying to determine if that is a bad design choice, and if instead the interface should actually be an object called "language", with a property of each language variable.

The entire game already uses this "import all language variables, declare a global variable, and echo it" coding throughout the game, so there isn't really a way to avoid code spread throughout the game. I'm just trying to develop a solid alternative that doesn't require 1400 global variables for a page that will only use 5.

I could do that with just a simple function that does a look-up for a variable name in a db table, or I could make it an object. I'm hoping for advice on which is a good choice (or if there is another choice I'm not thinking of).
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: OOP design question

Post by Benjamin »

The Phoenix wrote:What I'm trying to get at is whether the interface for accessing the language should be in the form of a variable, a function, or a class? My suspicion is that English is an extension of a Language object, and that I should be providing the interface that way. I'm just looking to others with more OOP experience to offer advice on whether I'm over-reaching a bit. :)
Well I think the better question here is what would you rather use, RAM, CPU or DISK IO? You can make the code feel pretty regardless.

Anyway, to answer your question, it would have to be an indexed array to get decent performance. You can wrap it in a class or just put it in an include file. No reason to add complexity.
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: OOP design question

Post by Benjamin »

Honestly I like my idea to compile versions of each file into each language.

For example this:

Code: Select all

<?php
echo "Hello {#WORLD}";
?>
<h1>{#MAIN_HEADING_HELLO_PAGE}</h1>
Would become this for the english version:

Code: Select all

<?php
echo "Hello World";
?>
<h1>This is an example</h1>
Then your template loader can just load the corresponding file and all the code remains intact. If you modify any code just recompile all the language files.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: OOP design question

Post by Christopher »

The Phoenix wrote:Since we're already recoding, I figured it was time to rethink key design decisions (like the language design).

Today, the "interface" for a programmer on the game wanting to get output that is translated to match the users desire is a variable. (That the variable is actually in the global scope is just insult to injury). I'm trying to determine if that is a bad design choice, and if instead the interface should actually be an object called "language", with a property of each language variable.
I might refactor it in two steps. First I would convert all the uses of "echo $l_return_main;" to some interface like "echo language('l_return_main');" or "echo $language->get('l_return_main');". That gets you to a place where you can actually refactor, because the program no longer cares what is going on inside that function -- only that it gets a string back.

The first refactor is essentially a find and replace that you could roll-out one part of the code at a time. Initially it might just use the global strings like:

Code: Select all

class Language
{
    public function get($text)
    {
         return $GLOBALS[$id];
      }
}
Admittedly that looks silly, but it gets you from A to B. Once you get the entire app using "echo $language->get('l_return_main');" then you can do whatever you want inside the class.
The Phoenix wrote:The entire game already uses this "import all language variables, declare a global variable, and echo it" coding throughout the game, so there isn't really a way to avoid code spread throughout the game. I'm just trying to develop a solid alternative that doesn't require 1400 global variables for a page that will only use 5.

I could do that with just a simple function that does a look-up for a variable name in a db table, or I could make it an object. I'm hoping for advice on which is a good choice (or if there is another choice I'm not thinking of).
Though I don't know much about this app, but I would go with an object from what what little I know. The reason is that I would rather make the language selection in the bootstrap and create an appropriate object than have hard coded calls to a function all over the code. The function would invariably need globals inside so it could be reconfigured.

An object injected into where needed would be more flexible for me because it could not only be loaded based on the language, but you could support multiple datasources easily (e.g. MySQL, SQLite, Memcached). Sure you could do that inside a function, but it seems like it would quickly become a mess.
(#10850)
User avatar
The Phoenix
Forum Contributor
Posts: 294
Joined: Fri Oct 06, 2006 8:12 pm

Re: OOP design question

Post by The Phoenix »

Great replies everyone, exactly what I was looking for. Thanks!
Post Reply