
Originally Posted by
BrightChoco
I have only released one snippet? It's not a "god" class, I have various classes for various functionality. So don't be so quick off your feet to assume so.
Sephern just because you can use MSSQL and MySQL at the same time in PHP doesn't mean that I will. I have other plans, and specific ones which require MSSQL, therefore I am using it.
More snippets will be released shortly to clear up the spoof about this being a "god" class and non Object Oriented coding.
Does anyone have any specific Item Mall suggestions? I am thinking just a basic Buy, Gift, and if you have suggestions for features I am open to them.
You've released one snippet, but the one snippet you have released is a 'god' class. You have several different functions in there, none of them necessarily related to each other.
Why have a parse_config function in a class which also connects to a database, does queries, generates hashes, and filters output?
A class should do one specific job. For example, have a config class which deals with parsing config files, and returning config values. A database class which handles connection to a database, querying and such. A security class maybe, which has output sanitization and hashing. Logically structuring your code into different blocks, which all do a specific thing is the whole purpose of Object Orientation.
As for your usage of MsSQL, I appreciate that you'll probably at some point be communicating with the game database. However, in a situation where web servers are being run separately from the game servers (which should be most of the time), MySQL will probably be the superior option for this development, for the following reasons.
1) It has better PHP support. PHP has better extensions for handling connections to MySQL (particularly the most excellent PDO Library). This leads to faster, more efficient and generally cleaner code.
2) MsSQL is locked down to Microsoft. This means that when you want to scale, you have to pay out. Lets say at the moment you're quite a small server who run your web box on the same server as your game. When it comes to the point where you want to split off and get a web box, you have to get Windows hosting, with MsSQL. When you go to get a VPS or Dedicated server, you have the same issue. You'll have to pay for a windows server license and a MsSQL license. Plus windows generally isn't as good as a Server Operating System in comparison to Linux.
3) MySQL is marginally quicker, and more memory efficient.
I'm not necessarily saying that you definitely should make it with MySQL. All I'm saying is that its something you should consider and not dismiss straight away. Adding support for multiple database engines, for example, probably won't take that long if you've designed your application with Object Orientation.
Also, we're giving you constructive criticism to help your project become better. It's all part of the learning process, we're not insulting you personally, just putting a few things you should look out for -.-
Edit: Oh, and the code snippets I was talking about before.
PHP Code:
<?php
#Cache Class
#Created by Sephern
#Allows parsing and easy retrieval of Config values
class Config {
protected static $is_loaded = false;
protected static $config_options = array();
public static function getVal($category, $key) {
if (self::$is_loaded === false)
{
$config = parse_ini_file("config.ini.php", true);
self::$is_loaded = true;
self::$config_options = $config;
return $config[$category][$key];
}
return self::$config_options[$category][$key];
}
}
?>
That's obviously a class for parsing config files. I'll probably add some support for caching later on, which is definitely something you should do if you plan to use this and implement caching in yours. At the moment it does one stat call per request D:
Caching it should be quite simple. Make a function which tries to make a call to APC. If it succeeds, then check if a cached value exists, and if it does then update the static variable to reflect the values from the cache, set that the static variable has been filled and return the value. If there is no cache record, get the ini file and cache it :)
PHP Code:
<?php
#Logging Abstraction Layer
#Created by Sephern
#Allows the user to log intuitive messages from anywhere in their application
class Log {
const LOG_ERROR = 5;
const LOG_WARN = 4;
const LOG_NOTICE = 3;
const LOG_INFO = 2;
const LOG_DEBUG = 1;
protected static $engine = false;
protected static $maxlevel = false;
public function __construct($engine = false) {
#Constructor to determine the logging engine
if ($engine === false)
$engine = strtolower(Config::getVal("log","engine"));
require_once ("log.".$engine.".php");
$loadlib = "Log".$engine."Wrapper";
$instance = new $loadlib();
self::$engine = $instance;
self::$maxlevel = Config::getVal("log","loglevel");
}
private static function _getInstance() {
#Create an instance of child logging engine class
if (!self::$engine)
{
$log = new Log();
}
return self::$engine;
}
private static function _write($loglevel, $message, $file, $line) {
#Write to the log
$log = self::_getInstance();
if ($loglevel <= self::$maxlevel)
{
if (!$file || !$line)
{
$location = debug_backtrace();
$file = $location[1]['file'];
$line = $location[1]['line'];
}
$log->write($loglevel, $message, $file, $line);
}
}
public static function error($message, $file=false, $line=false) {
#public method for errors
self::_write(self::LOG_ERROR, $message, $file, $line);
}
public static function warn($message, $file=false, $line=false) {
#public method for warnings
self::_write(self::LOG_WARN, $message, $file, $line);
}
public static function notice($message, $file=false, $line=false) {
#public method for notices
self::_write(self::LOG_NOTICE, $message, $file, $line);
}
public static function info($message, $file=false, $line=false) {
#public method for information messages
self::_write(self::LOG_INFO, $message, $file, $line);
}
public static function debug($message, $file=false, $line=false) {
#public method for debugging messages
self::_write(self::LOG_DEBUG, $message, $file, $line);
}
}
?>
Abstraction code for logging. This basically allows you to have multiple different 'engines' for logging, as specified in the config file. Evidently, if you do your configs differently from mine (and choose to only have one logging engine) yours will be different.
The advantage of this is that as it abstracts, you can change the code really easily. Simply by writing a new 'engine' and changing the config file, you can have it save errors in a database, email a site admin, and do a ton of other stuff. When you have the logging engine called by the error handler, it can be really quite powerful. Especially since you don't have to go through all the code and change it, and you can switch back to different file logging methods with the change of 1 config line.
PHP Code:
<?php
#Log File Engine
#Created by Sephern
#Class for logging to a file - written for logging abstraction layer
class LogFileWrapper {
private $fhandle;
public function __construct() {
#Determine whether the logfile exists, and create/open for editing
$logdir = Config::getVal("log", "logdir");
if ($logdir[0] != "/")
$logdir = "/".$logdir;
$logdir = $_SERVER['DOCUMENT_ROOT'].Config::getVal("general","path").$logdir."/log-".date("d.m.y").".log";
$this->fhandle = fopen($logdir, 'at');
}
public function write($loglevel, $message, $file, $line) {
#Write to the logfile
switch($loglevel)
{
case Log::LOG_ERROR:
$level = "ERROR";
break;
case Log::LOG_WARN:
$level = "WARNING";
break;
case Log::LOG_NOTICE:
$level = "NOTICE";
break;
case Log::LOG_INFO:
$level = "INFORMATION";
break;
case Log::LOG_DEBUG:
$level = "DEBUG";
break;
}
$time_format = strval(Config::getVal("log","timestamp_format"));
$timestamp = date($time_format, time());
$fullmessage = "[".$level."] - ".$timestamp." - ".$message." in ".$file." on line ".$line."\n\n";
fwrite($this->fhandle, $fullmessage);
return true;
}
public function __destruct() {
#Close the handle on class ending to prevent file lockups
fclose($this->fhandle);
}
}
?>
Theres an example of an engine. Its a pretty basic one that writes to files.
The logging mechanism uses Log4j, which is pretty much industry standard. It specifies 5 levels of error that you can log within your application.
PHP Code:
;<?php die("Direct File Access Forbidden"); ?>
;Framework Configuration Script
;Windows Ini Format
;Comments declared with semi-colons
;Trees are enclosed in square brackets
;Settings stored in key value pairs
[general]
path = /Framework ;any folder or path outside of the document root, with leading slash
[database]
host = localhost ;your db host, IP or DNS
port = 3306 ;the port your database runs on
username = root ;your database username
password = ****** ;your database password
schema = testdb ;your schema/database name
engine = MySQL ;your database engine [MySQL, MsSQL]
returntype = ROW ;default return type of queries. [ROW, ARRAY, VALUE, RAW]
table_prefix = ;table prefix for your db tables
[log]
engine = File ;logging engine, currently only File
logdir = /Logs ;goes from the document root, and a leading slash should be used (but will be silently added if there isn't one)
fileprefix =
; 0 = no logging
; 1 = log errors
; 2 = log warnings
; 3 = log notices
; 4 = log info
; 5 = log debug
; all escalate
loglevel = 5
timestamp_format = d/m/Y G:i:s
[errors]
showinfo = true ;Show error information in error pages displayed to user. Should be set to false in production environment (True/False)
[cache]
engine = memcached
host = localhost
port = 11211
ttl = 600 ;time for cache records to survive by default in seconds
Finally, a sample config.php.
All of these are called as static, so all you need to do is include/require them in your project (so probably just adding them to your autoloader).
PHP Code:
Config::getVal("database", "host");
would return the database host in the config. Its pretty simple. The first argument passed to it is the section of the config (the bits in square brackets), and the second part is the key. The function returns the value.
Logging takes 1 parameter which is compulsory, and 2 optional ones. Obviously, the parameter you have to send is the message.
PHP Code:
Log::debug("This is a log message");
You can also optionally send a file name, and a line number
PHP Code:
log::error("Shit! Something went wrong", "anotherfile.php", 12);
Hopefully those little snippets should help you out when it comes to coding the same segments of your application ;)