dbevfat wrote:I only write procedural code when prototyping...
I've got some code that smells. There are times when I'm in a hurry or tired and I hack something together.
I just had a read about OOP at wikipedia which states that:
http://en.wikipedia.org/wiki/Object-oriented_programming wrote:Object-oriented programming may be seen as a collection of cooperating objects, as opposed to a traditional view in which a program may be seen as a group of tasks to compute ("subroutines"). In OOP, each object is capable of receiving messages, processing data, and sending messages to other objects.
Each object can be viewed as an independent little machine with a distinct role or responsibility. The actions or "operators" on the objects are closely associated with the object. For example, in OOP, the data structures tend to carry their own operators around with them (or at least "inherit" them from a similar object or "class"). The traditional approach tends to view and consider data and behavior separately.
So when I compare this to how I program I can see that I am using classes correctly. The major difference between me and most programmers however is the "style" in which I use them. I have been writing my own framework (like tons of other programmers have done, I know) in order to significantly increase development time. It's called the Accelerated Development Framework Environment or ADEF.
It contains a collection of useful classes, does not adhere to MVC, and provides unique ways to easily accomplish complicated tasks.
I've posted below a page from a site I built using the framework. This is the the contents of the entire register.php file. I have changed some of the field names. I posted this because it's the ugliest bit of code in the entire site. This page is the guts of a 3 step registration process where the URL does not change. ie the url is always
http://site.com/register regardless of what the page is displaying. The first page asks the user for some basic information, the second page asks for some more and allows for an avatar upload (it captures the image even if other fields on the form fail validation and displays it), and the third page asks for some more information. The second and third pages can be skipped by clicking a link. I think that a lot of things are accomplished for only 207 lines of code.
Code: Select all
<?php
# cookies are required here
session_test($_KERNEL->paths->get('RESOLVED_REQUEST'), 'cookies');
# process registration skips
if (get('skip') != '')
{
switch (get('skip'))
{
case '2':
# display registration step 3
$_KERNEL->compiler->change_destination('registration_step_3');
return;
break;
case '3':
# redirect to member's home page
redirect('members/');
break;
}
}
# process any posted data
if (post('do_action') != '')
{
switch (post('do_action'))
{
case 'new_registration':
if ($_KERNEL->member_validation->new_registration())
{
# was the account created ok?
if(false !== ($member_data = $_KERNEL->member_accounts->create_account()))
{
# send welcome e-mail including activation code
$_KERNEL->email_notify->send_member_message($member_data, 'new_account_welcome');
# log the user in
$_KERNEL->member_authentication->login($member_data['email_address']);
# display registration step 2
$_KERNEL->compiler->change_destination('registration_step_2');
return;
} else {
# shouldn't end up here unless **** hits the fan someplace
$_KERNEL->status->error("An internal error has occurred. Please try again.");
}
} else {
# validation failure
$_KERNEL->status->error($_KERNEL->form_errors->get_errors());
}
break;
case 'save_step_two':
# get the member data
if (!$member_data = $_KERNEL->member_authentication->get_cur_user_data())
{
$_KERNEL->status->error("Your session data has expired. Please login or restart the registration process.");
redirect('register');
}
try {
# process the file upload:
$_KERNEL->upload->set_option('MAX_UPLOAD_SIZE', 6244640);
$_KERNEL->upload->set_option('ALLOWED_EXTENSIONS', array('jpg', 'jpeg', 'gif', 'png'));
$_KERNEL->upload->set_option('OVERWRITE_IF_EXIST', true);
# create an image name
$image_name = $member_data['member_id'] . '_' . SITE_ID . '_' . random_string(5);
# if an image was uploaded process it
if ($_FILES['avatar']['error'] != 4)
{
# if an existing image exists, delete it if this upload succeeds
if (!empty($member_data['avatar']))
{
$old_avatar = $member_data['avatar'];
}
# save the uploaded image
if (!$temp_image = $_KERNEL->upload->save_file('avatar', AVATAR_SYS_PATH, "$image_name.tmp"))
{
throw new Exception($_KERNEL->upload->get_error());
}
# resize the uploaded image
if (false === ($resized = $_KERNEL->resize_image->process_resize(AVATAR_MAX_HEIGHT, AVATAR_MAX_WIDTH, AVATAR_SYS_PATH.$temp_image, AVATAR_SYS_PATH."$image_name.jpg")))
{
throw new Exception("There was a problem resizing your image. Please try again or try a different image.");
}
list($new_width, $new_height) = $resized;
unset($resized);
# delete the tmp image
if (file_exists(AVATAR_SYS_PATH.$temp_image))
{
unlink(AVATAR_SYS_PATH.$temp_image);
}
# delete the old image
if (file_exists(AVATAR_SYS_PATH.$old_avatar) && $old_avatar != "$image_name.jpg")
{
unlink(AVATAR_SYS_PATH.$old_avatar);
}
# set the permissions
chmod(AVATAR_SYS_PATH."$image_name.jpg", '0644');
# everything is ok with the image, we can save it now
$data = array('avatar' => "$image_name.jpg",
'av_width' => $new_width,
'av_height' => $new_height);
$_KERNEL->member_data->update($member_data['email_address'], $data);
}
} catch (Exception $e) {
# clean up
if (file_exists(AVATAR_SYS_PATH.$temp_image))
{
unlink(AVATAR_SYS_PATH.$temp_image);
}
# set the error messages
$_KERNEL->status->error($e->getMessage());
}
try {
# validate the rest of the form
if (!$_KERNEL->member_validation->registration_step_2())
{
$_KERNEL->status->error($_KERNEL->form_errors->get_errors());
throw new Exception();
}
# update the members data in db
$data = array('field_one' => post('field_one'),
'field_two' => post('field_two'),
'field_three' => post('field_three'),
'field_four' => post('field_four'));
# this is sent through the member_data class which will also update memcache
$_KERNEL->member_data->update($member_data['email_address'], $data);
# display registration step 3
$_KERNEL->compiler->change_destination('registration_step_3');
return;
} catch (Exception $e) {
# set the error messages
$_KERNEL->status->error($e->getMessage());
# redisplay registration step 2
$_KERNEL->compiler->change_destination('registration_step_2');
return;
}
break;
case 'save_step_three':
# get the member data
if (!$member_data = $_KERNEL->member_authentication->get_cur_user_data())
{
$_KERNEL->status->error("Your session data has expired. Please login or restart the registration process.");
redirect('register');
}
try {
# validate the rest of the form
if (!$_KERNEL->member_validation->registration_step_3())
{
throw new Exception();
}
# remove any and all html
$_POST = array_map('no_html', $_POST);
# update the member_profile table
$data = array('field_one' => compress(post('field_one')),
'field_two' => compress(post('field_two')),
'field_three' => compress(post('field_three')),
'field_four' => compress(post('field_four')),
'field_five' => post('field_five'),
'field_six' => post('field_six'),
'field_sev' => compress(post('field_sev')));
$_KERNEL->db->update($data, 'member_profile', array('member_id' => "= {$member_data['member_id']}"));
# redirect to member's home page
redirect('members/');
} catch (Exception $e) {
# set the error messages
$_KERNEL->status->error($_KERNEL->form_errors->get_errors());
# redisplay registration step 2
$_KERNEL->compiler->change_destination('registration_step_3');
return;
}
break;
}
} else {
$_POST['country_id'] = '223';
}
# the authentication mechanism requires that the user is logged
# out before an account can be created.
if ($member_data = $_KERNEL->member_authentication->get_cur_user_data())
{
$_KERNEL->compiler->change_destination('register_must_logoff');
return;
}
?>
<h1>Register New Account</h1>
<form name="register" method="post" action="register">
<table class="form" cellspacing="0">
<tr>
<td class="label"><label for="first_name">First name:</label></td>
<td><?php echo input('first_name'); ?></td>
</tr>
<tr>
<td class="label"><label for="last_name">Last name:</label></td>
<td><?php echo input('last_name'); ?></td>
</tr>
<tr>
<td class="label"><label for="email_address">Email address:</label></td>
<td><?php echo input('email_address'); ?></td>
</tr>
<tr>
<td class="label"><label for="password">Password:</label></td>
<td><?php echo password('password'); ?></td>
</tr>
<tr>
<td class="label"><label for="confirm_password">Retype Password:</label></td>
<td><?php echo password('confirm_password'); ?></td>
</tr>
<tr>
<td class="label">Date of Birth:</td>
<td><?php echo select('month', get_month_array()); ?> / <?php echo select('day', get_date_array()); ?> / <?php echo select('year', get_year_array()); ?> </td>
</tr>
<tr>
<td class="label"><label for="country_id">Country:</label></td>
<td><?php echo select('country_id', get_country_array()); ?></td>
</tr>
<tr>
<td class="label"><label for="postal_code">Postal code:</label></td>
<td><?php echo input('postal_code'); ?></td>
</tr>
<tr>
<td class="label"><label for="gender">Gender:</label></td>
<td><?php echo radio('gender', 'male', 'Male'), radio('gender', 'female', 'Female'); ?></td>
</tr>
<tr>
<td class="label"> </td>
<td><?php echo checkbox('tos_agree', 'I have read and agree to the <a href="tos" title="View our terms of service">terms of service</a>'); ?></td>
</tr>
<tr>
<td colspan="2" class="submit">
<input type="hidden" name="do_action" value="new_registration" />
<button type="submit">Sign Up</button>
</td>
</tr>
</table>
</form>
Now as you can see, I'm using classes (reusable) to do a lot of the grunt work, but I haven't gone purely OO on this page because I think a majority of the sequences on this page are a one shot deal. Generally I don't put something into a class if I don't see any benefit from making it reusable. There have of course been times when I was wrong, in which case I refactored the code.
Just so the code is easier to understand.
$_KERNEL->classname calls a class, if the class isn't instantiated yet it is on the fly, passing arguments to the construct is not possible.
$_KERNEL->compiler->change_destination('page_name') changes the http request. So if you request index and change it to contact, the contact page is processed and displayed without redirecting, and index is still displayed in the url
$_KERNEL->status-> sets a success or error message, this message will be displayed even if you change_destination or do a hard redirect
The form_errors class tracks which fields contain errors and these fields are automatically assigned an error class via there respective function calls, ie input for an input box, select for a select menu.
pytrin wrote:I write entirely OO as well...
I read your article. I would say that I write code to be as simple as possible, sometimes to the extreme, but I definitely do not write code to refactor it. The last thing I want to do is rewrite code I have already written. Not because I don't want to touch code that "works" but rather I don't want to waste time. I'm not saying I don't or won't, I just try to avoid it. I'd push doing it right the first time over refactoring any day.