15 Things Schools Won’t Teach You About Programming

Comments 4 Standard
15 things you won't learn about programming in school

Don’t get me wrong, going to school to learn how to program is great but there are some things that schools seem to miss the mark on and these drive me nuts.

  1. Copying – well yes, cheating is bad and you should do your own work in school but it’s also not reasonable to expect someone to go it alone on a project in a job setting. Your manager won’t ask you to live in a bubble of seclusion when they want you to complete a difficult task in a short amount of time. In fact they’ll encourage you to use outside resources and other programmers to get the job done. This is one of my worst pet-peeves about schools. Sure you need to know how to program but in the real world you aren’t required to go it alone without any kind of external resources at your disposal or the collaborative programming with other co-workers.
  2. Scope Creep – so in school your projects have a nicely defined list of features and requirements your professor wants you to implement. However the real world isn’t so nice and cut and paste — even if you have well developed requirements. The fact of the matter is you often won’t know what requirements you need to fulfill until you stub out some kind of prototype and show it to your clients and get their feedback. In addition you’ll typically find things that you didn’t think about which make you scratch your head and go back to the drawing board a time or two.
  3. Text Book Solutions – if you’ve ever done an assignment from a textbook with an answer key in the back you know exactly what I’m talking about. There’s always that one solution that’s deemed the “correct” answer. In reality there often isn’t a single solution to a problem and what may work as a solution in one environment is a complete and utter failure in another as the scale or complexity or speed of the results actually hinder the user experience.
  4. Making The Grade – everyone knows you’re supposed to get straight A’s in order to get a good job after school. Wrong! I’ve never known an employer to ask for a GPA or how many times I failed a class. The truth is your grades don’t matter, it’s your knowledge and experience that count. So what if you have straight A’s in every class you ever took if you’ve never had any practical experience building your own program or working on a large, complex project. No one cares what your grades are, they want to know you can get the work done well and in a timely fashion with minimal bugs.
  5. Re-Inventing The Wheel – yes it’s important that you understand how and why something works but schools are notorious for having their students re-invent the wheel. Let’s write five different types of searches that most languages have built in functionality for, or let’s write a function that swaps two values so you can use it in later projects. Please, don’t re-invent the wheel. If it’s already done for you then why are you wasting your time? Understand how it works and then take that knowledge and build something useful, don’t just regurgitate what’s already been done over and over again.
  6. Debugging – this is one of the most useful skills you can have and yet schools are sadly lacking in teaching students how to intelligently debug errors and use helpful debugging tools. In addition most schools stress actual programming when even the software life-cycle emphasizes maintenance and  bug fixing as a majority of the time spent on piece of software. Why are schools leaving this out of their curriculum when most new programmers are tasked with bug fixes in order to learn how a large piece of software works?
  7. Documentation – there is a sad lack of acknowledgement for documentation in programming. Some schools will skim over it briefly but for the most part it’s a passing reference in a class. I’m amazed at how many new programmers I interact with who have thousands and thousands of lines of code without a single comment. Now some of you may argue that documentation isn’t needed however if you’ve ever returned to work on a project you set down years ago you know those hours you spent trying to figure out why you did something that you didn’t document could have been better spent with the 5 minutes documenting it in the first place.
  8. Deadlines – in school you’re given long deadlines to get something done. Deadlines aren’t as set and fixed in a job setting. One day your boss may walk up to you and say “I need this in an hour.” If you’re always used to long, drawn out deadlines then you get that deer in the headlights look in your eyes. Of course this works both ways, and I’ve worked on projects that have no deadlines either. The point to take away from this is deadlines are flexible and rigid, achievable and impossible to meet and not a fixed point in time and space.
  9. Multitasking – in school you only work on a single project at a time until that project is done. A job setting is far from that. You may start a project one day, have it scrapped the next day and then returned to you six months later. In addition it’s common to be working on multiple projects at a time as you wait for other requirements or client feedback to trickle in. Asking students to work on one project at a time is detrimental to them learning how to multitask and adjust as the situation warrants.
  10. Pass or Fail – schools have a pretty black and white approach to how a program is supposed to work in order for you to get a passing grade. What they forget is often times a project just needs to be “good enough” due to deadlines or budgets or resource constraints. Something that is good enough to meet the requirements doesn’t mean you failed, it means you have room for improvement and re-factoring.
  11. Refactoring – I would love to see a school tell a student to take the first project they completed at the beginning of the year and re-write it with what they know now. Re-factoring is a major aspect of a programmer’s job and yet few students are asked to look at their past work, reflect on how it could be improved, and then set to the task of improving it. This is something most programmers are faced with on a yearly basis as they complete new iterations and features of their software.
  12. Coding Together – since schools are so intent on grading you as an individual the students miss out on the ability to code collaboratively. There is rarely a time when a complete piece of large software will have been written by a single person. Being able to read and understand other people’s programming and to match your style to theirs is a huge asset and ability that shouldn’t be overlooked.
  13. Best Coding Practices – so you learn the programming fundamentals but you’re hardly taught when you should use one rather than the other and where, how or why you make that decision.
  14. Code Style Guidelines – one of the biggest indications of a good programmer is their coding style. Code that is easy to read, indented properly, and consistently written is essential for improving maintainability of a piece of software. Most new programmers run their lines of code in big long strings with inconsistent spacing and style guidelines. Would you rather read 1,200 lines of code condensed onto 5 lines that makes you scroll infinitely in your editor to read them or properly indented and spaced code in a logical and easy to read manner? I know which one I’d choose.
  15. Experience – there is no substitute for real experience. No school can give you anything more than an introduction to programming no matter if you spend a year or four years learning and expanding your knowledge. There’s a wonderful article by Peter Norivg that I like to give anyone whose interested in making programming a profession. You can’t take ten years of experience and condense it into a quick fix or four year series of courses. Experience will always be your best teacher.

Got a few minutes? Check out the best tools to test your websites responsiveness.

Angular Autocomplete with Complex Object Arrays — NO JQUERY

Leave a comment Link

There are many times when you want to perform an autocomplete that works by searching all of the object properties and not just a single field or the key. If so you’ll enjoy this plunker.

Angular Js

Leave a comment Standard
AngularJS

I wrote a few plunkers this past month that I thought I would share for anyone whose interested in dabbling in Angular JS. Enjoy!

PHP Function: Posted Time Ago – Facebook Style

Leave a comment Standard

So I won’t claim credit to this but I was browsing DevNetwork and I found a function that is both useful, succinct and awesome all rolled up into one. Using a php lookup table you can calculate the time since something was posted in PHP ie “so and so posted x time ago” facebook style.

function time_passed($timestamp)
{
     $diff = time() - (int)$timestamp;

     if ($diff == 0) 
          return 'just now';

     $intervals = array
     (
         1                   => array('year',    31556926),
         $diff < 31556926    => array('month',   2628000),
         $diff < 2629744     => array('week',    604800),
         $diff < 604800      => array('day',     86400),
         $diff < 86400       => array('hour',    3600),
         $diff < 3600        => array('minute',  60),
         $diff < 60          => array('second',  1)
     );

      $value = floor($diff/$intervals[1][1]);
      return $value.' '.$intervals[1][0].($value > 1 ? 's' : '').' ago';
}

FREE PHP Tool: Class File Generator

Comment 1 Standard

Want to quickly generate a class file for a table in your database? This script takes your connection information, the name of the table, the name of your class and gives you a formatted class file you can download and use in a snap. Features include the ability to add get/set methods for each field, a simple debugger, and a print object function. It’s available under the GNU public license.

Download the Class File Generator

The Source Code

<?php
/*********
* File: index.php
* Date: 4.5.2012
* Author: design1online.com, LLC
* Purpose: generate a oop class file for a mysql database table
*********/
DEFINE("AUTHOR", "Design1online.com, LLC");

if ($_POST['generate'])
{
    $fields = array();
    $keys = array();

    if (!$_POST['host'])
        $_POST['host'] = "localhost";

    //connect to the database
    mysql_connect ($_POST['host'], $_POST['username'], $_POST['pass'])
        or die ('Cannot connect to the database: ' . mysql_error());

    mysql_select_db ($_POST['db'])
        or die ('Cannot select database: ' . mysql_error()); 

    $table = mysql_query("SHOW columns FROM {$_POST['table']}")
        or die ('Cannot load table: ' . mysql_error());

    //load the table fields and keys
    while ($schema = mysql_fetch_assoc($table))
    {

        $field = array(
            "name" => $schema['Field'],
            "type" => $schema['Type']
        );

        if ($schema['Key'])
            array_push($keys, $field);

        array_push($fields, $field);
    }

    $filename = ($_POST['name']) ? $_POST['name'] : $_POST['table'];

    //build the file
    $file = "/**********
* File: $filename.class.php
* Author: " . AUTHOR . "
* Created: " . date('n.j.Y g:ia') . "
* Free PHP Class Generator: http://design1online.com/phpclassfilegenerator
**********/

class $filename";

    if ($_POST['extends'])
        $file .= " extends {$_POST['extends']}";

    $file .= " {\n\n";

    if ($_POST['vars'])
    {
        foreach ($fields as $index => $field)
            $file .= "\tvar $" . $field['name'] . ";\n";
    }

    if ($_POST['debug'])
        $file .= "\tvar \$debugger = false;\n";

    $file .= "\n\t/*********
\t* Purpose: Default constructor
\t* Preconditions: None
\t* Postconditions: None
\t*********/
\tfunction $filename(";

    foreach ($keys as $index => $field)
        $keynames[] = $field['name'];

    //build the constructor parameters
    if ($_POST['constructor'])
        $file .= "$" . implode(", $", $keynames);

    $file .= ") {\n";

    if ($_POST['debug'])
        $file .= "\n\t\tif (\$this->debugger)\n\t\t\techo \"DEBUGGER: initializing $filename object\";\n";

    //build the constructor
    if ($_POST['constructor'])
    {
        foreach ($keys as $index => $field)
        {
            $file .= "\n\t\tif (!$" . $field['name'];

            if (strpos($field['type'], "int") !== false || strpos($field['type'], "decimal") !== false
                || strpos($field['type'], "float") !== false || strpos($field['type'], "double") !== false
                || strpos($field['type'], "real") !== false || strpos($field['type'], "bit") !== false
                || strpos($field['type'], "bit") !== false || strpos($field['type'], "bool") !== false
                || strpos($field['type'], "serial") !== false)
                    $file .= " || !is_numeric($" . $field['name'] . ")";

            $file .= ")\n\t\t\treturn;\n";
        }

        $file .= "\n\t\t\$result = mysql_query(\"SELECT * FROM {$_POST['table']} WHERE ";

        $append = false;

        foreach ($keys as $index => $field)
        {    
            if ($append)
                $file .= " AND ";

            $file .= "{$field['name']} = '$" . $field['name'] . "'";

            if (!$append)
                $append = true;
        }

        $file .= "\")\n\t\t\tor die('Cannot init constructor in $filename.class.php: ' . mysql_error());\n\n\t\t\$row = mysql_fetch_assoc(\$result);\n";

        foreach ($fields as $index => $value)
        {
            $file .= "\n\t\t\$this->{$value['name']} = ";

            if (strpos($value['type'], "varchar") !== false || strpos($value['type'], "text") !== false
                || strpos($value['type'], "blob") !== false || strpos($value['type'], "enum") !== false
                || strpos($value['type'], "set") !== false || strpos($value['type'], "binary") !== false)
                    $file .= "stripslashes(html_entity_decode(";

            $file .= "\$row['{$value['name']}']";

            if (strpos($value['type'], "varchar") !== false || strpos($value['type'], "text") !== false
                || strpos($value['type'], "blob") !== false || strpos($value['type'], "enum") !== false
                || strpos($value['type'], "set") !== false || strpos($value['type'], "binary") !== false)
                    $file .= ", ENT_QUOTES))";

            $file .= ";";
        }
    }

    $file .= "\n\n\t} //end default constructor";

    //check to see if they want the print function
    if ($_POST['print'])
    {
        $file .= "\n\n\t/*********
\t* Purpose: Display the object
\t* Preconditions: None
\t* Postconditions: None
\t*********/
\tfunction print() {";

        if ($_POST['debug'])
            $file .= "\n\n\t\tif (\$this->debugger)\n\t\t\techo \"DEBUGGER: printing $filename object\";";

        $file .= "\n\n\t\techo \"<b>Displaying $filename Object</b><br/><br/>";

        foreach ($fields as $index => $value)
            $file .= "\n\t\t\t{$value['name']} = \$this->{$value['name']}<br/>";

        $file .= "\";\n\n\t} //end print function";
    }

    //check to see if they want the get methods
    if ($_POST['get'])
    {
        foreach ($fields as $index => $value)
        {
            $file .= "\n\n\t/*********
\t* Purpose: Get the value from the {$value['name']} field
\t* Preconditions: None
\t* Postconditions: {$value['name']} field value returned
\t*********/
\tfunction get" . ucFirst($value['name']) . "() {";

            if ($_POST['debug'])
                $file .= "\n\n\t\tif (\$this->debugger)\n\t\t\techo \"DEBUGGER: calling {$filename}->get" . ucFirst($value['name']) . " method\";\n";

            $file .= "\n\t\treturn \$this->{$value['name']};\n\t}";

        }
    }

    //check to see if they want the set methods
    if ($_POST['set'])
    {
        foreach ($fields as $index => $value)
        {
            $file .= "\n\n\t/*********
\t* Purpose: Set the value of the {$value['name']} field
\t* Preconditions: None
\t* Postconditions: object and table data set to \$value
\t*********/
\tfunction set" . ucFirst($value['name']) . "(\$value) {";

            if ($_POST['debug'])
                $file .= "\n\n\t\tif (\$this->debugger)\n\t\t\techo \"DEBUGGER: calling {$filename}->get" . ucFirst($value['name']) . " method\";";

            $file .= "\n\n\t\tif (!\$value)\n\t\t\treturn \"Invalid value\";

\t\tmysql_query(\"UPDATE {$_POST['table']} SET {$value['name']}='\$value' WHERE ";

            $append = false;

            foreach ($keys as $index => $field)
            {    
                if ($append)
                    $file .= " AND ";

                $file .= "{$field['name']} = '\$this->" . $field['name'] . "'";

                if (!$append)
                    $append = true;
            }

            $file .= "\")\n\t\t\tor die('Cannot set value for {$value['name']}: ' . mysql_error());\n\n\t\t\$this->{$value['name']} = \$value;\n\t}";

        }
    }

    $file .= "\n\n} //end $filename.class.php";

    //setup the headers so you can download the file
    header('Content-type: text');
    header("Content-Disposition: attachment; filename=$filename.class.php");
    echo $file;
}

if (!$_POST['generate'])
{
    echo "
    <center>
    <h1>Class File Generator</h1>
    <form action=\"#\" method=\"post\">
        <table cellpadding=\"2\" cellspacing=\"2\" width=\"80%\">
            <tr>
                <th>MySQL Connection</th>
                <th>Class Options</th>
            </tr>
            <tr>
                <td width=\"50%\" valign=\"top\">
                    <p>Host: <input type=\"text\" name=\"host\" value=\"{$_POST['host']}\" /></p>
                    <p>Username: <input type=\"text\" name=\"username\" value=\"{$_POST['username']}\" /></p>
                    <p>Password: <input type=\"password\" name=\"pass\" value=\"{$_POST['pass']}\" /></p>
                    <p>Database: <input type=\"text\" name=\"db\" value=\"{$_POST['db']}\" /></p>
                    <p>Table: <input type=\"text\" name=\"table\" value=\"{$_POST['table']}\" /></p>
                    <p align=\"center\">
                        <input type=\"submit\" name=\"generate\" value=\"Generate Class\" />
                    </p>
                </td>
                <td>
                    <p>
                        Class Name: <input type=\"text\" name=\"name\" value=\"{$_POST['name']}\" />
                        <br/><i>tablename used by default</i>
                    </p>
                    <p>
                        Extends Class: <input type=\"text\" name=\"extends\" value=\"{$_POST['extends']}\" />
                        <i>(optional)</i>
                    </p>
                    <blockquote>
                        <p><input type=\"checkbox\" name=\"vars\" checked=\"checked\" />Include variable declarations</p>
                        <p><input type=\"checkbox\" name=\"constructor\" checked=\"checked\" />Include default constructor</p>
                        <p><input type=\"checkbox\" name=\"get\" />Include get functions for all fields</p>
                        <p><input type=\"checkbox\" name=\"set\" />Include set functions for all fields</p>
                        <p><input type=\"checkbox\" name=\"print\" />Include print function</p>
                        <p><input type=\"checkbox\" name=\"debug\" />Include debugger</p>
                    </blockquote>
                </td>
            </tr>
        </table>
        <p>
            <a href=\"http://design1online.com/downloads/classfilegenerator.zip\">Download Source Code</a><br/>
                <b>GNU Public License</b>
        </p>
        <p>
            <a href=\"http://design1online.com\">by design1online.com, LLC</a>
        </p>
    </form>
    </center>";

PHP Tutorial: Free OOP Hangman Game (no database required)

Comments 8 Standard

At this year’s Siminar I’m presenting a live webinar on “Learning OOP” to many young female gamers. Part of that presentation includes a OOP hangman game they can easily install and incorporate on their existing websites. There is no database required, the only software requirements are php version 4 or higher. To get this game running all you have to do is upload the files to a folder on your website then edit the config/wordlist.txt file.

Getting Started

If you take a minute to think about it most games have a few things in common. So we’re going to start by making a class that has all the attributes and methods use in any generic game. For instance, most games keep track of the score, the player’s health, whether or not they’ve won the game and if they’ve had a game over. These are things we don’t want to write over and over again with every game we make so we’ll make one generic class for methods and attributes most games have in common.

Now we can use this generic class to extend any other game we make in the future. Extending a class means one class, the child, will inherit all of the attributes and methods of the other class, the parent. Our generic game class is a parent class of a specific game class for our hangman game. For more information on classes or if you want a refresher course on OOP programming I suggest you read this tutorial.

The Game Class

Our game class contains all of our generic attributes and methods. These are things we expect any game we make might have so we can use this game class over and over again. Because this game class will be extended by other classes it’s known as a parent class.

<?php

class game {

    var $health;    //int - player's health
    var $over;        //bool - toggle game over
    var $score;        //int - player's score
    var $won;        //bool - toggle game won

    /**
    * Purpose: setup game environment variables
    * Preconditions: turn the debugger on (optional)
    * Postconditions: the game environment is ready to start a game
    **/
    function start()
    {
        $this->score = 0;
        $this->health = 100;
        $this->over = false;
        $this->won = false;
    }

    /**
    * Purpose: end the game
    * Preconditions: turns on the game over flag
    * Postconditions: game over flag is true
    **/
    function end()
    {
        $this->over = true;
    }

    /**
    * Purpose: change or retrieve the player's score
    * Preconditions: amount (optional)
    * Postconditions: returns the player's updated score
    **/
    function setScore($amount = 0)
    {
        return $this->score += $amount;
    }

    /**
    * Purpose: change or retrieve the player's health
    * Preconditions: amount (optional)
    * Postconditions: returns the player's updated health
    **/
    function setHealth($amount = 0)
    {            
        return ceil($this->health += $amount);
    }

    /**
    * Purpose: return bool to indiciate whether or not the game is over
    * Preconditions: none
    * Postconditions: returns true or flase
    **/
    function isOver()
    {
        if ($this->won)
            return true;

        if ($this->over)
            return true;

        if ($this->health < 0)
            return true;

        return false;
    }

} //end game class

/**
* Purpose: display a formatted debug message
* Preconditions: the object or message to display
* Postconditions: returns the player's updated score
**/
function debug($object = NULL, $msg = "")
{
    if (isset($object) || isset($msg))
    {
        echo "<pre>";

        if (isset($object))
            print_r($object);

        if (isset($msg))
            echo "\n\t$msg\n";

        echo "\n</pre>";
    }
}

/**
* Purpose: return a formatted error message
* Preconditions: the message to format
* Postconditions: formatted message is returned
**/
function errorMsg($msg)
{
    return "
$msg
"; } /** * Purpose: return a formatted success message * Preconditions: the message to format * Postconditions: formatted message is returned **/ function successMsg($msg) {     return "
$msg
"; }

The Hangman Class

This is the most complicated part of our hangman game. The hangman class will drive all of our game setup, loading, and respond to the user’s entry choices. We’ve extended it so that it will inherit all of the attributes and methods we’ve created in our game class. This way we don’t have to write those attributes and methods over and over again each time we create a new game.

Overall this file is split into three main parts. The loading of the game is done by the newGame() method. This loads our word list from a separate file and then randomly selects a word for the player to guess. It also resets the player’s score and letter guesses in case they play again once the first game is over.

The second part of the file displays or drives the game in the playGame() method. It decides whether or not to start a new game, respond to a letter that was guessed, show error messages and check to see if they guess the right word or if they’ve run out of guesses.

The last part two methods in the file are helper methods. isLetter() checks to make sure they’ve entered a valid letter in the alphabet and wprdToArray converts our word to an array so we can compare it with the letters they’ve guessed so far.

<?php

class hangman extends game
{
    var $guesses;                //int - maximum guesses per word
    var $letters = array();        //array - letters guessed so far
    var $wordIndex;                //int - index of the current word
    var $wordLetters = array();    //array - array of the letters in the word
    var $wordList = array();    //array - list of words they can guess

    var $alphabet = array(        //array - all letters in the alphabet
        "a", "b", "c", "d", "e", "f", "g", "h",
        "i", "j", "k", "l", "m", "n", "o", "p",
        "q", "r", "s", "t", "u", "v", "w", "x",
        "y", "z");

    var $punctuation = array(    //array - punctuation marks in the word list
        " ", "\,", "\'", "\"", "\/", "\\", "\[",
        "\]", "\+", "\-", "\_", "\=", "\!", "\~",
        "\~", "\@", "\.", "\?", "\$", "\#", "\%",
        "\^", "\&", "\*", "\(", "\)", "\{", "\}",
        "\|", "\:", "\;");

    /**
    * Purpose: default constructor
    * Preconditions: none
    * Postconditions: parent object started
    **/
    function __construct()
    {
        /**
        * instantiate the parent game class so this class
        * inherits all of the game class's attributes
        * and methods
        **/
        game::start();
    }

    /**
    * Purpose: start a new hangman game
    * Preconditions: maximum number of guesses
    * Postconditions: game is ready to be displayed
    **/
    function newGame($max_guesses = 5)
    {
        //setup the game
        $this->start();

        //make sure we clear out the last letters they guessed
        $this->letters = array();

        //set how many guesses they get before it's a game over
        if ($max_guesses)
            $this->setGuesses($max_guesses);

        //pick a word for them to try and guess
        $this->setWord();
    }

    /**
    * Purpose: set or retrieve maximum guesses before game over
    * Preconditions:
    * Postconditions:
    **/
    function playGame($game)
    {
        //player pressed the button to start a new game
        if (isset($game['newgame']) || empty($this->wordList))
            $this->newGame();

        //player is trying to guess a letter
        if (!$this->isOver() && isset($game['letter']))
            echo $this->guessLetter($game['letter']);

        //display the game
        $this->displayGame();
    }

    /**
    * Purpose: set or retrieve maximum guesses they can make
    * Preconditions: amount of guesses (optional)
    * Postconditions: guesses has been updated
    **/
    function setGuesses($amount = 0)
    {        
        $this->guesses += $amount;
    }

    /**
    * Purpose: display the game interface
    * Preconditions: none
    * Postconditions: start a game or keep playing the current game
    **/
    function displayGame()
    {
        //while the game isn't over
        if (!$this->isOver())
        {
            echo "
" . $this->picture() . "
                 
" . $this->solvedWord() . "
                 
                    Enter A Letter:                                                                    
";                   if (!empty($this->letters))                     echo "
Letters Guessed: " . implode($this->letters, ", ") . "
";         }         else         {             //they've won the game             if ($this->won)                 echo successMsg("Congratulations! You've won the game.<br/>                                 Your final score was: $this->score");             else if ($this->health < 0)             {                 echo errorMsg("Game Over! Good try.<br/>                                 Your final score was: $this->score");                 echo "
" . $this->picture() . "
";             }             echo "
";         }     }     /**     * Purpose: guess a letter in this word     * Preconditions: a game has started     * Postconditions: the game data is updated     **/     function guessLetter($letter)     {                     if ($this->isOver())             return;         if (!is_string($letter) || strlen($letter) != 1 || !$this->isLetter($letter))             return errorMsg("Oops! Please enter a letter.");         //check if they've already guessed the letter         if (in_array($letter, $this->letters))             return errorMsg("Oops! You've already guessed this letter.");         //only allow lowercase letters         $letter = strtolower($letter);         //if the word contains this letter         if (!(strpos($this->wordList[$this->wordIndex], $letter) === false))         {             //increase their score based on how many guesses they've used so far             if ($this->health > (100/ceil($this->guesses/5)))                 $this->setScore(5);             else if ($this->health > (100/ceil($this->guesses/4)))                 $this->setScore(4);             else if ($this->health > (100/ceil($this->guesses/3)))                 $this->setScore(3);             else if ($this->health > (100/ceil($this->guesses/2)))                 $this->setScore(2);             else                 $this->setScore(1);             //add the letter to the letters array             array_push($this->letters, $letter);             //if they've found all the letters in this word             if (implode(array_intersect($this->wordLetters, $this->letters), "") ==                 str_replace($this->punctuation, "", strtolower($this->wordList[$this->wordIndex])))                 $this->won = true;             else                 return successMsg("Good guess, that's correct!");         }         else //word doesn't contain the letter         {             //reduce their health             $this->setHealth(ceil(100/$this->guesses) * -1);             //add the letter to the letters array             array_push($this->letters, $letter);             if ($this->isOver())                 return;             else                 return errorMsg("There are no letter $letter's in this word.");         }     }     /**     * Purpose: pick a random word to try and solve     * Preconditions: none     * Postconditions: if the word exists a word index has been set     **/     function setWord()     {         //if the word list is empty we need to load it first         if (empty($this->wordList))             $this->loadWords();         //reset the word index to a new word         if (!empty($this->wordList))             $this->wordIndex = rand(0, count($this->wordList)-1);         //convert the string to an array we can use         $this->wordToArray();     }     /**     * Purpose: load the words from the config file into an array     * Preconditions: filename to load the words from (optional)     * Postconditions: the word list has been loaded     **/     function loadWords($filename = "config/wordlist.txt")     {         if (file_exists($filename))         {             $fstream = fopen($filename, "r");             while ($word = fscanf($fstream, "%s %s %s %s %s %s %s %s %s %s\n")) {                 $phrase = "";                 if (is_string($word[0]))                 {                     foreach ($word as $value)                         $phrase .= $value . " ";                     array_push($this->wordList, trim($phrase));                 }             }         }     }     /**     * Purpose: return the image that should be displayed with this number of wrong guesses     * Preconditions: none     * Postconditions: picture returned     **/     function picture()     {         $count = 1;         for ($i = 100; $i >= 0; $i-= ceil(100/$this->guesses))         {             if ($this->health == $i)             {                 if (file_exists("images/" . ($count-1) . ".jpg"))                     return "<img src=\"images/" . ($count-1) . ".jpg\" alt=\"Hangman\" title=\"Hangman\" />";                 else                     return "ERROR: images/" . ($count-1) . ".jpg is missing from the hangman images folder.";             }             $count++;         }         return "<img src=\"images/" . ($count-1) . ".jpg\" alt=\"Hangman\" title=\"Hangman\" />";     }     /**     * Purpose: display the part of the word they've solved so far     * Preconditions: a word has been set using setWord()     * Postconditions: the letters they've guessed correctly show up     **/     function solvedWord()     {         $result = "";         for ($i = 0; $i < count($this->wordLetters); $i++)         {             $found = false;             foreach($this->letters as $letter) {                 if ($letter == $this->wordLetters[$i])                 {                     $result .= $this->wordLetters[$i]; //they've guessed this letter                     $found = true;                 }             }             if (!$found && $this->isLetter($this->wordLetters[$i]))                 $result .= "_"; //they haven't guessed this letter             else if (!$found) //this is a space or non-alpha character             {                 //make spaces more noticable                 if ($this->wordLetters[$i] == " ")                     $result .= "&nbsp;&nbsp;&nbsp;";                 else                     $result .= $this->wordLetters[$i];             }         }         return $result;     }     /**     * Purpose: convert the selected word to an array     * Preconditions: a word has been selected     * Postconditions: wordLetters now contains an array representation of the     *    selected word     **/     function wordToArray()     {         $this->wordLetters = array();         for ($i = 0; $i < strlen($this->wordList[$this->wordIndex]); $i++)             array_push($this->wordLetters, $this->wordList[$this->wordIndex][$i]);     }     /**     * Purpose: check to see if this value is a letter     * Preconditions: value to check     * Postconditions: returns true if letter found     **/     function isLetter($value)     {         if (in_array($value, $this->alphabet))             return true;         return false;     } }

Playing The Game

Now that we have our classes in place we need to create a file that instantiates, or creates, the hangman object. We’ll save our object to a session so we don’t loose the player’s data as they refresh the page. Finally we call the hangman’s playGame() method passing it the $_POST data so we know how to respond to the buttons they’ve clicked.

//include the required files
require_once('oop/class.game.php');
require_once('oop/class.hangman.php');

//this will keep the game data as they refresh the page
session_start();

//if they haven't started a game yet let's load one
if (!isset($_SESSION['game']['hangman'])) {
    $_SESSION['game']['hangman'] = new hangman();
}
?>
<html>
    <head>
        <title>Hangman</title>
        <link rel="stylesheet" type="text/css" href="inc/style.css" />
    </head>
    <body>
        
        " method="POST">         

Let's Play Hangman!

        playGame($_POST); }       ?>              
    </body> </html>

Conclusion

Try the working version! In this tutorial we created two classes, a game class and a hangman class. Because all games have several aspects in common we’ve extended our game class to make our hangman class. This way we can use the attributes and methods of the game class for other games we might make in the future. When our classes were done we created a final file to load and store the game data in a session so we don’t loose it as the page reloads and then told the game to display itself by calling the playGame() method.

Download The Source

Get the .zip archive

PHP Tutorial: Learning OOP – Class Basics & Extending Classes

Comments 8 Standard

What Is OOP?

Object Oriented Programming (OOP) is an programming style that uses classes with attributes and methods to create objects. OOP can be used anywhere, however it’s most practical when working with relational database models or on projects where major aspects of the programming can be classified as objects.

What Is An Object?

An object is defined by a class. It has attributes and methods that describes the characteristics and actions it can perform.
  • Attribute – are commonly the objects appearance, characteristics, limitations or abilities. For example size, weight, height, shape, color, speed, hunger, and health are all attributes of an animal.
  • Methods – an action the object can perform. For example eat, sleep, drink, breed, hibernate, buy something, and equip an item are all actions an object might perform.

Class Basics

A class is a good way to abstract lots of smaller details from a bigger picture. For instance, let’s take a second to think about a vending machine. There are lots of different parts that make up a vending machine, but all combined together we only think of the vending machine as one complete unit, or object. A class uses the same kind of idea, lots of smaller parts making a bigger object.

For instance a vending machine has multiple attributes like size, shape, color, make, model and manufacturer. It also has many actions  it can perform such as responding to a button press, calculating the correct change, dispensing the change, refunding money, accepting a two letter code for an item, checking to see if there are items in that entry, dispensing the item if it has one or returning an error message. We can use classes to define the properties (attributes) and actions (methods) the vending machine can perform in PHP.

Since the vending machine is a bit more complicated than I want to get in this tutorial I’m going to choose something easier to start off with.

Fruit Class

We all know there are several different types of fruit but they all have some common characteristics. For instance all fruit has a name, color, size, and varying degrees of sweetness. These are the attributes we’re going to use for our fruit class.

Now let’s think about the kind of actions you can perform with fruit.  You can wash them, eat them and shine them to name a few. We’re going to use these actions as methods in our class.

Using this really simple break down, let’s make our fruit class:

<?php
class fruit
{
 //here are the attributes of our class
 var $name;
 var $color;
 var $size;
 var $sweet;
 var $clean;
 var $washed;

function fruit($name)
{
 //this is a default constructor. It always has the same name
 //as the class. Whenever we
 //make a fruit object this function is automatically called

 $this->name = $name; //we automatically give this fruit its name
 $this->clean = False; //our fruit always needs to be washed first
 $this->washed = 0; //we haven’t washed it any times yet
}

//but we want to be able to set other things about the fruit
function setColor($color)
{
 $this->color = $color;
}

function setSize($size)
{
 $this->size = $size;
}

function setSweet($sweet)
{
 $this->sweet = $sweet;
}

//lets make a way to wash our fruit
function wash()
{
 $this->clean = True; //our fruit is clean now
 $this->washed++; //we’ve washed our fruit one more time
}

//we want to eat our fruit now
function eat()
{
  if (!$this->clean)
    echo "You should always wash your $this->color $this->name first!!!";

 if ($this->clean && $this->washed < 2)
   echo "You’re eating a dull looking piece of $this->name...";

 if ($this->clean && $this->washed >= 2)
   echo "You're eating a shiny piece of $this->color $this->name!";

 if (!$this->clean && $this->washed >= 2)
   echo "Your $this->name is shiny but you probably should wash it first.";

 if ($this->sweet)
   echo "This fruit is sweet.";
 else
   echo "This fruit is classified as a vegetable!";
}

//we can make a shine function, that washes the surface of the fruit as well
function shine()
{
 $this->washed++;
}
} //end of our class

//let's make an orange
$orange = new fruit("Orange");
$orange->setSize("small");
$orange->setColor("orange");
$orange->setSweet(True);

//now we'll make a watermelon
$fruit = new fruit("Watermelon");
$fruit->setSize("large");
$fruit->setColor("green");
$fruit->setSweet(True);

//last but not least we'll make a tomato (which is also a fruit!)
$veggie = new fruit("Tomato");
$veggie->setSize("medium");
$veggie->setColor("red");
$veggie->setSweet(False);

echo "Washing my $orange->name.";
$orange->wash();

echo "<br>Eating my $veggie->size $veggie->name.";
$veggie->eat();

echo "<br/>Washing my $orange->name again.";
$orange->wash();

echo "<br/>Shining my $fruit->size $fruit->name.";
$fruit->shine();

echo "<br/>Eating my $fruit->name.";
$fruit->eat();

echo "<br/>Eating my $orange->size $orange->name.";
$orange->eat();

//let's see what the structure of our objects looks like
//this is useful when you're trying to find or fix a problem

print_r($orange);
echo "<br/><br/>";

print_r($fruit);
echo "<br/><br/>";

print_r($veggie);
echo "<br/><br/>";

?>

Try running this script. What happens? One of the neatest things about a class is any method you make can be applied to any object of that class. In the example above we had three different fruit objects. Even though they were all different objects they used the same methods of the fruit class and stored their own data.

You’ll also notice we can directly access or change the attributes of the class using the -> arrow the same way we call a method.

Up for a challenge?

  1. Try adding more methods to this class.
  2. Try making $veggie = $fruit. What happens when you do $veggie->name now?
  3. Try adding a method that lets you set all attributes (color, sweet, size) at the same time.
  4. What happens if you to access a method or attribute that doesn’t exist in the class?
    1. Try writing $fruit->sell();
    2. Try echoing $fruit->weight;
  5. What happens if you pass one object as a parameter to another object’s method?
    1. Add this method:

function splice($otherfruit)
{
echo “I’m trying to splice ” . $this->name . ” with this ” . $otherfruit->name . “.”;
}

Test your new method  by adding $orange->splice($fruit); to the bottom of your file.

Extending Classes

I think of an extended class as a shortcut to programming similar objects. Other people, and your traditional programming school books, will tell you it’s a class that extends the functionality of an existing class. It may also be referred to as a sub-class or child class.

Programatically an extended class is easy to create. Take this example:

class car {
  var $make;
  var $model;
  var $shift_auto;
  var $horsepower;
  var $color;
  var $fuel;
  var $mpg;

  function drive($distance)
  {
     if ($fuel - $distance > 0)
     {
       $fuel -= $distance;
       echo "Driving $distance miles";
     }
     else
       echo "You don't have enough gas to go that far.";
  }

  function refuel($amount)
  {
    $fuel += $amount;
  }

}

Our car class gives us some information about the car and the ability to drive and refuel. Now look at this extended class:

class truck extends car { 

  var $tow_capacity;
  var $has_hitch;

  function tow_vehicle($car_object)
  {
     return "Towing a " . $car_object->make . " " . $car_object->model;
  }
}

In our extended class, we automatically have all the functions and variables from the car class, but we’ve also added the ability to tow another vehicle. Try making another extended class called sportscars. What additional variables or functions do you think you’d add?

Default & Optional Parameter Values

One of the neatest things about PHP is the ability to have an optional method parameter just like you can with regular functions. Let’s refer back to our fruit class and add this method:

function fruit($type, $color = "red", size = null)
{

   if (!$size)
   {
      switch(rand(1, 3))
      {
           case 1: $size = "small";
               break;
           case 2: $size = "medium";
               break;
           case 3: $size = "large";
               break;
       }

       echo "$size $color $type<br/>";
}

Can you figure out how this method works on your own? If not that’s okay too! All of the examples below are acceptable ways to call this method:

fruit(“cherry”) — returns {size} red cherry where size is randomly selected.

fruit (“bananna”, “yellow”) — returns {size} yellow bannana where size is randomly selected.

fruit(“plumb”, “purple”, “small”) — returns small purple plum.

This fruit class now has the ability to create an object with some of the attributes set for you. It has two optional parameters, one default parameter and one required parameter. The type of fruit is required. The color of the fruit is optional, but if you don’t specify a color it will automatically default to red. The size of the fruit is also optional, but if you don’t give it a size then the function will randomly pick one.

What makes these parameters optional? We’ve assigned them to a value right in the method’s parameter list. However this doesn’t prevent us from changing the value by passing in our own.

Conclusion

In this tutorial we covered some of the basic principles of OOP and classes. You learned that classes define the abilities of an object and have both attributes and methods. You also learned how to extend a class so it inherits the attributes and methods of another class. Finally you learned how to make your methods take optional parameters or default values.

Think you have the hang of it now? Test your skills by creating a game using a class! If you get stuck you can always read this Free OOP Hangman Game Tutorial (no database required).

Are you still a bit unsure about the whole thing? That’s okay! Now you can quickly and easily generate class files based off of a table in your database using our new PHP Class File Generator Tutorial.