From the category archives:

PHP

This semester I’m going to have my Ruby and PHP classes build a form driven, AJAX-y web application as the final project. This is a bread-and-butter assignment that performs the basic task of storing form data in a database then displaying it. We’ll deal with the ever present Persistence Problem by using a SQLite3 database to store user input, and the AJAX/Javascript layer will be all JQuery.

I’ve created the PHP proof of concept site at http://www.istoasisto.com, and it looks like this:

A classroom project of this size can be completed in four to six weeks, depending on the programming and web skills a student brings to the class. More is always better.

The PHP course will be starting from scratch (no cakePHP, no Drupal, no Joomla), while my Ruby course will be using Rails. I’ll be doing the project in Seaside. When all is said and done, we will count the lines of PHP, Ruby, and Smalltalk to see who get bragging rights for writing the fewest lines of code.

If you want to work along wtih us, your project should have these features:

  • An HTML form.
  • JQuery form manipulation.
  • AJAX via JQuery.
  • Validated form input.
  • Form data stored in a SQLite database.
  • A Recaptcha form.
  • User data safely displayed (potentially harmful characters sanitized).

There are dozens of features we could hang on this skeleton: pagination, search, social features (Twitter, Facebook, Buzz, etc), as well as polls, voting, thumbs-up/down, email, XML export, RSS feeds, Section 508 compliance, and more. I’ll be satisfied if most of my students can achieve basic functionality before semester burnout sets in.

And about that Seaside course—there isn’t one yet. But it is on my TODO list for future courses at CCSF. For the time being, as part of my own Smalltalk education, I’ll take this opportunity to complete the class project using Seaside. Since Smalltalk and Seaside are new to me, I’ll be starting on the same page as my PHP and Ruby students. This will be fun. I’ll be doing this project with Cincom Visualworks Non-Commercial which is free for non-commercial use on Windows, Linux, and Mac OS X.

OK. I’d better get to work on the Ruby part of this project before the Rails team unleashes another new product release just to confuse me.

Happy hacking…

{ 4 comments }

A reserved word in a programming language is a word that is off limits to the programmer. For example, in PHP print is a reserved word. This means that you, as the programmer, cannot create a function named print because PHP owns that word.

Most languages have reserved words, some a few, and some very, very many. Usually the fewer reserved words a language has, the more flexible it is. For example, in the list below, you will see that Lisp has no reserved words. We all know that Lisp is very flexible and powerful.

As you look at the table below, do not think unkind thoughts about PHP—it’s different from the other languages. It is not designed to be a general purpose programming language, though it can certainly do almost anything you want it to do. It is intended for web programming, which explains the existence of so many of the predefined functions and constants. Those are exactly the kinds of items that other languages must implement individually if they want to be as handy with web development as PHP. This is no small task, kids. Just take a look around try to find a web site implemented in C++.

Reserved Words

Language Count Reserved Words
Lisp 0 Lisp has no reserved words. Lisp is written in Lisp. Alan Kay, the creator of Smalltalk, said: “Lisp isn’t a language, it’s a building material.”
Smalltalk 5 self super nil true false
C 32 auto break case chart const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while
C++ ~62 and and_eq asm auto bitand bitor bool break case catch char class compl const const_cast continue default delete do double dynamic_cast else enum explicit export extern false float for friend goto if inline int long mutable namespace new not not_eq operator or or_eq private protected public register reinterpret_cast return short signed sizeof static static_cast struct switch template this throw true try typedef typeid typename union unsigned using virtual void volatile wchar_t while xor xor_eq
Ruby 38 alias and BEGIN begin break case class def defined? do else elsif END end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield
Python 31 and del from not while as elif global or with assert else if pass yield break except import print class exec in raise continue finally is return def for lambda try
Java 47 abstract do if package synchronized boolean double implements private this break else import protected throw byte extends instanceof public throws case false int return transient catch final interface short true char finally long static try class float native strictfp void const for new super volatile continue goto null switch while default assert
PHP 418 __CLASS__ __COMPILER_HALT_OFFSET__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __PHP_INCOMPLETE_CLASS ABDAY_1 ABDAY_2 ABDAY_3 ABDAY_4 ABDAY_5 ABDAY_6 ABDAY_7 ABMON_1 ABMON_10 ABMON_11 ABMON_12 ABMON_2 ABMON_3 ABMON_4 ABMON_5 ABMON_6 ABMON_7 ABMON_8 ABMON_9 ABSTRACT ALT_DIGITS AM_STR AND ARGC ARGV ARRAY AS ASSERT_ACTIVE ASSERT_BAIL ASSERT_CALLBACK  ASSERT_QUIET_EVAL ASSERT_WARNING AUTH_TYPE BREAK CASE CASE_LOWER CASE_UPPER CATCH CFUNCTION CHAR_MAX CLASS CLONE CODESET CONNECTION_ABORTED CONNECTION_NORMAL CONNECTION_TIMEOUT CONST CONTINUE COUNT_NORMAL COUNT_RECURSIVE CREDITS_ALL CREDITS_DOCS CREDITS_FULLPAGE CREDITS_GENERAL CREDITS_GROUP CREDITS_MODULES CREDITS_QA CREDITS_SAPI CRNCYSTR CRYPT_BLOWFISH CRYPT_EXT_DES CRYPT_MD5 CRYPT_SALT_LENGTH CRYPT_STD_DES CURRENCY_SYMBOL D_FMT D_T_FMT DAY_1 DAY_2 DAY_3 DAY_4 DAY_5 DAY_6 DAY_7 DECIMAL_POINT DECLARE DEFAULT DEFAULT_INCLUDE_PATH DIE DIRECTORY_SEPARATOR DO DOCUMENT_ROOT E_ALL E_COMPILE_ERROR E_COMPILE_WARNING E_CORE_ERROR E_CORE_WARNING E_ERROR E_NOTICE E_PARSE E_STRICT E_USER_ERROR E_USER_NOTICE E_USER_WARNING E_WARNING ECHO ELSE ELSEIF EMPTY ENDDECLARE ENDFOR ENDFOREACH ENDIF ENDSWITCH ENDWHILE  ENT_COMPAT ENT_NOQUOTES ENT_QUOTES ERA ERA_D_FMT ERA_D_T_FMT ERA_T_FMT ERA_YEAR EVAL EXCEPTION EXIT EXTENDS EXTR_IF_EXISTS EXTR_OVERWRITE EXTR_PREFIX_ALL EXTR_PREFIX_IF_EXISTS EXTR_PREFIX_INVALID EXTR_PREFIX_SAME EXTR_SKIP FINAL FOR FOREACH FRAC_DIGITS FUNCTION GATEWAY_INTERFACE GLOBAL GROUPING HTML_ENTITIES HTML_SPECIALCHARS HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_CONNECTION HTTP_HOST HTTP_REFERER HTTP_USER_AGENT HTTPS IF IMPLEMENTS INCLUDE INCLUDE_ONCE INFO_ALL INFO_CONFIGURATION INFO_CREDITS INFO_ENVIRONMENT INFO_GENERAL INFO_LICENSE INFO_MODULES INFO_VARIABLES INI_ALL INI_PERDIR INI_SYSTEM INI_USER INT_CURR_SYMBOL INT_FRAC_DIGITS INTERFACE ISSET LC_ALL LC_COLLATE LC_CTYPE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LIST LOCK_EX LOCK_NB LOCK_SH LOCK_UN LOG_ALERT LOG_AUTH LOG_AUTHPRIV LOG_CONS LOG_CRIT LOG_CRON LOG_DAEMON LOG_DEBUG LOG_EMERG LOG_ERR LOG_INFO LOG_KERN LOG_LOCAL0 LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_LPR LOG_MAIL LOG_NDELAY LOG_NEWS LOG_NOTICE LOG_NOWAIT LOG_ODELAY LOG_PERROR LOG_PID LOG_SYSLOG LOG_USER LOG_UUCP LOG_WARNING M_1_PI M_2_PI M_2_SQRTPI M_E M_LN10 M_LN2 M_LOG10E M_LOG2E M_PI M_PI_2 M_PI_4 M_SQRT1_2 M_SQRT2 MON_1 MON_10 MON_11 MON_12 MON_2 MON_3 MON_4 MON_5 MON_6 MON_7 MON_8 MON_9 MON_DECIMAL_POINT MON_GROUPING MON_THOUSANDS_SEP N_CS_PRECEDES N_SEP_BY_SPACE N_SIGN_POSN NEGATIVE_SIGN NEW NOEXPR NOSTR OLD_FUNCTION OR P_CS_PRECEDES P_SEP_BY_SPACE P_SIGN_POSN PATH_SEPARATOR PATH_TRANSLATED PATHINFO_BASENAME PATHINFO_DIR NAME PATHINFO_EXTENSION PEAR_EXTENSION_DIR PEAR_INSTALL_DIR PHP_AUTH_DIGEST PHP_AUTH_PW PHP_AUTH_USER PHP_BINDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_DATADIR PHP_EOL PHP_EXTENSION_DIR PHP_INT_MAX PHP_INT_SIZE PHP_LIBDIR PHP_LOCALSTATEDIR PHP_OS PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_END PHP_OUTPUT_HANDLER_START PHP_PREFIX PHP_SAPI PHP_SELF PHP_SHLIB_SUFFIX PHP_SYSCONFDIR PHP_USER_FILTER PHP_USER_FILTER PHP_VERSION PM_STR POSITIVE_SIGN PRINT PRIVATE PROTECTED PUBLIC QUERY_STRING RADIXCHAR REMOTE_ADDR REMOTE_HOST REMOTE_PORT REQUEST_METHOD REQUEST_TIME REQUEST_URI REQUIRE REQUIRE_ONCE RETURN SCRIPT_FILENAME SCRIPT_NAME SEEK_CUR SEEK_END SEEK_SET SERVER_ADDR SERVER_ADMIN SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SIGNATURE SERVER_SOFTWARE SORT_ASC SORT_DESC SORT_NUMERIC SORT_REGULAR SORT_STRING STATIC STDCLASS STR_PAD_BOTH STR_PAD_LEFT STR_PAD_RIGHT SWITCH T_FMT T_FMT_AMPM THIS THOUSANDS_SEP THOUSEP THROW TRY UNSET USE VAR WHILE XOR YESEXPR YESSTR LASS__ __COMPILER_HALT_OFFSET__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __PHP_INCOMPLETE_CLASS ABDAY_1 ABDAY_2 ABDAY_3 ABDAY_4 ABDAY_5 ABDAY_6 ABDAY_7 ABMON_1 ABMON_10 ABMON_11 ABMON_12 ABMON_2 ABMON_3 ABMON_4 ABMON_5 ABMON_6 ABMON_7 ABMON_8 ABMON_9 ABSTRACT ALT_DIGITS AM_STR AND ARGC ARGV ARRAY AS ASSERT_ACTIVE ASSERT_BAIL ASSERT_CALLBACK ASSERT_QUIET_EVAL ASSERT_WARNING AUTH_TYPE BREAK CASE CASE_LOWER CASE_UPPER CATCH CFUNCTION CHAR_MAX CLASS CLONE CODESET CONNECTION_ABORTED CONNECTION_NORMAL CONNECTION_TIMEOUT CONST CONTINUE COUNT_NORMAL COUNT_RECURSIVE CREDITS_ALL CREDITS_DOCS CREDITS_FULLPAGE CREDITS_GENERAL CREDITS_GROUP CREDITS_MODULES CREDITS_QA CREDITS_SAPI CRNCYSTR CRYPT_BLOWFISH CRYPT_EXT_DES CRYPT_MD5 CRYPT_SALT_LENGTH CRYPT_STD_DES CURRENCY_SYMBOL D_FMT D_T_FMT DAY_1 DAY_2 DAY_3

{ 11 comments }

Web development used to be a relatively simple corner of computer science — in 1995. This is what we’re dealing with now.

Web development -- a hot mess of PHP and everything else

No wonder web development seems complicated...

{ 0 comments }

My current technology preoccupations are PHP, Ruby, and Smalltalk. Over the last month I’ve been putting together blog sites for each of them: PHP: The Good Parts, Ruby: The Good Parts, and Smalltalk: The Good Parts.

I spend most of my time with PHP and Ruby because I teach classes in these languages at CCSF and CSM. After years of teaching both beginning students and experienced professionals I have an accurate sense of what they need to get off to a good start. I’ve written a ton of content for these courses—screencasts, pdfs, projects, exercises, etc. I plan to use the PHP and Ruby blogs to share some of the material I’ve created for my courses.

Smalltalk is a different matter: I’m a complete newbie and I’m climbing the same learning curve that my PHP and Ruby students climb. As I learn Smalltalk I’ll use the blog to document the process. My plan is to turn my experience (blood, sweat, and tears) into a Smalltalk course. I’ve seen Smalltalk in action, and now I want to do it for myself, then show others how insanely great it is.

I’ll be adding content to the blogs as I as fast as I can proof read it and test the code. If you are on the front end of your PHP career, you will find some pearls of wisdom here. I suggest that you subscribe to these blogs to keep informed of new posts as I update these blogs.

It’s going to take time to fill in these pages, and I expect that I’ll make many errors along the way. I appreciate all feedback; if you see something that needs fixing—code errors, spelling errors, or something that’s just plain wrong—please let me know. Feedback is golden.

Keep hacking…

Respect

My good parts blogs are inspired by Javascript: The Good Parts by Douglas Crockford. His cogent little book has taught me to scrutinize programming languages with a pragmatic eye: embrace what works and find a way to deal with the rest.

{ 0 comments }

Variable Variables

by doug on January 11, 2010

in PHP

In PHP parlance a variable variable is a variable that holds a the name of another variable of any data type. In other words, a variable variable is an example of dynamic typing, or duck typing. Dynamic typing and duck typing are two features that get a lot of attention in object oriented languages like Ruby and Python because they’re useful for doing magic tricks. Rather than muddy the water be talking of this mysterious thing called magic, I’ll call it what it is: dynamic typing.

Although dynamic typing is one of PHP’s most useful features, beginning PHP programmers can find it confusing. The terminology itself—variable variables—is a little too clever to be useful. Moreover, when variable variables are discussed, they are usually shown in non-productive examples, like this:

1    $place  = 'The Big Apple'; // $place can be written ${place}
2    $holder = 'place';         // Holds the name of the $place variable
3    echo $$holder;             // ==> The Big Apple


How it works

In line 1 we assign the value “The Big Apple” to $place.
In line 2 we assign $holder the value ‘place.’
But what’s going on with the ‘$$‘ in line 3? This bit of syntax is where PHP processes the variable variable.

Let’s consider how PHP handles line 3.

3    echo $$holder;

First, we need to remind ourselves that PHP parses each line from right to left. When PHP encounters the ‘$$‘, it processes the rightmost ‘$’ first. We can illustrate this by rewriting our code to wrap the first occurence in braces:

${$holder} ~ ${${holder}} ~ $$holder   // these three forms are equivalent

We can take this one step further and do variable substitution on $holder. In expressions, PHP replaces ‘$‘ variables with the values they refer to. In this case, ‘$holder‘ will be dereferenced and the value “place” will replace it. Now our code looks like this:

${'place'}

We still have the leftmost ‘$‘ and the ‘place‘ within the braces, which becomes:

$place


A synopsis of the process would look like this:

       6             5          4            3             2            1
'The Big Apple' ~ $place ~ ${'place'} ~ ${$holder} ~ ${${holder}} ~ $$holder

Although this example shows the process of using variable variables, it doesn’t give us a reason to use them in our programs. To see how to make use of variable variables, we need to see a few more examples.

What’s in a Variable?
In a dynamically typed language, it turns out that variables don’t really hold anything in particular. PHP variables simply point to something stored at some area of memory in your program. That something might be a string, a number, a filehandle, or any other kind of object. Whatever happens to be at the target location is available through the variable. Because variables are able to refer to any kind of PHP data type, we can do some of those so-called magical things quite conveniently.

Variables Used as Functions
In the following example, we will use variables to refer to the names of some functions.

Let’s assume for a moment that we have to create an HTML table using a multi-dimensional array that contains arrays of names.These arrays could be created by a query to a database, or they could be created from any other source. Our script will not care where the arrays came from. Our job is to put the names in each array into an HTML row, with each element encased in <td> tags, and the tags for each row encased in <tr> tags, all within containing <table> tags.

The array looks like this:

<?php
/** An array of names in an orderly format, as from a database. */
$names = array(
array('al', 'bob','cary','dave','ed'),
array('fred', 'george','harriet','isadore','jake'),
array('karen', 'louise','marion','ned','olive'),
array('paul', 'quincy','rhoda','sarah','terry'),
array('unknown', 'vera','whitey','xavier','zed')
);
?>

There are lots of ways to solve this problem, but for this example we’ll use variable variables to process a list of functions.

<?php

/**
* Create some HTML function
*/

/** Creates <td> elements. */
function td($array) {
$out = array();
foreach($array as $k => $a) {
  $out[] = "    <td>" . implode("</td>\n    <td>", $a) . "</td>\n";
}
return $out;
}

/** Creates <tr> elements using <td> elements. */
function tr($tds) {
$out = '';
foreach($tds as $row) {
  $out .= "  <tr>\n" . $row . '  </tr>'."\n";
}
return $out;
}

/** Creates a table using <tr> elements. */
function table($trs){
return '<table>' . "\n" . $trs . '</table>' . "\n";
}

/**
* The function names are entered in the array
* in the order that they will be executed.
*/
$funcs = array('td','tr','table');

/** Feed the $input array to the functions. */
$input = $names;
foreach($funcs as $function) {
$input = $function($input);
}
?>

<h1>Names</h1>
<?php echo $input ?>

The output:

<h1>Names</h1>
<table border>
  <tr>
    <td>al</td>
    <td>bob</td>
    <td>cary</td>
    <td>dave</td>
    <td>ed</td>
  </tr>
  <tr>
    <td>fred</td>
    <td>george</td>
    <td>harriet</td>
    <td>isadore</td>
    <td>jake</td>
  </tr>
  <tr>
    <td>karen</td>
    <td>louise</td>
    <td>marion</td>
    <td>ned</td>
    <td>olive</td>
  </tr>
  <tr>
    <td>paul</td>
    <td>quincy</td>
    <td>rhoda</td>
    <td>sarah</td>
    <td>terry</td>
  </tr>
  <tr>
    <td>unknown</td>
    <td>vera</td>
    <td>whitey</td>
    <td>xavier</td>
    <td>zed</td>
  </tr>
</table>

Run this code yourself to see the little table that pops out of this code. You can see that each function in the array is run as when $func refers to it. The value passed into the function is the value returned by the previous function. By the way, print() and echo() are not functions, so this technique will not work with them.

Next
In the next PHP Good Part we’ll extend variable variables a little further to create pretty URLs.

Until then, keep hacking…
–Douglas Putnam


{ 1 comment }

The Singleton Design Pattern in PHP

by doug on January 9, 2010

in PHP

The Singleton design pattern creates a class that can only have one instance. This is useful for tasks such as creating a globally available database connection for your script.

The prototype for the singleton class, in PHP, goes like this:

Singleton Pattern

class ClassName {     static $instance = NULL;     private function __construct() {}     private function __clone() {}     static function getInstance() {         if(self::$instance === NULL) self::$instance = new ClassName();         return self::$instance;     }

     $obj = ClassName::getInstance();}

In PHP, variables have scope restrictions that prevent them from being visible in all parts of your program. We often need these variables inside classes and functions, for example. One way to provide globally accessible variables is to pass them into classes or functions as parameters. This method makes it clear that the function of class method is dependent on an external variable or object. Here’s an example:

Option #1: Pass the Variable As A Parameter

Here’s an example of passing a database handle into a hypothetical function and into a class.

function logger($info, $dbhandle);

class Logger {    static $handle = NULL;    static function logIt($info, $dbhandle) {         self::$handle = $dbhandle;    }}

When you have only a few parameters this tactic works fine, but if your functions have many parameters the result is unwieldly code. It is not uncommon to find programmers creating functions or methods that have parameteritis, with dozens of confusing parameters.

Fortunately, a singleton class provides a cleaner solution: it provides global availability of a single object—with the side-effect that the sole object cannot be modified. If we want to ensure that this class cannot be cloned or sub-classed, we will mark it as final and the construct() and clone() methods as protected.

Option #2: Use a Singleton Class

Here’s an example a properly formed singleton class that cannot be cloned or sub-classed, ensuring that there will only be one instance of this class.

final class DbConnection {

    private static $handle = null;    private static $instance = NULL;    private static $db = 'default.db';

    // Deny new DbConnection();    private function __construct($db = NULL) {} 

    // We deny cloning, as with:     //     $instance = DbConnection::connect();    //     $clone = $instance;    private function __clone() {} 

    function connect() {        if(is_null(self::$handle)) {            if(defined('DEFAULT_DB') {                self::$db = DEFAULT_DB;            }            // Create the only possible instance of this class            self::$handle = new SqliteDatabase(self::$db);        }        return self::$handle;    }

    static function getInstance() {        if(self::$instance === NULL) {            self::$instance = new DbConnection();        }        return self::$instance;    }}

This class encapsulates the entire process of creating the single instance and the database handle, and checks to see if a default database constant exists. We can use it this way:

class Logger {    // Notice that this, too, is a singleton pattern class.    static private $logger = NULL;

    static function logIt($it) {        $dbc = DbConnection::getInstance()->connect();        if(self::$instance == NULL) {             self::$instance = new Logger);        }    }

    private function __construct() {}

}

Refactoring

Since the sole function of the DbConnection class is to provide a database connection, we can simplify the code considerably by eliminating the getInstance() method:

final class DbConnection {

    private static $handle = null;    private static $db = 'default.db';

    // Deny new DbConnection();    private function __construct($db = NULL) {} 

    // We deny cloning    private function __clone() {} 

    function connect() {        if(is_null(self::$handle)) {            if(defined('DEFAULT_DB') {                self::$db = DEFAULT_DB;            }            // Create the only possible instance of this class            self::$handle = new SqliteDatabase(self::$db);        }        return self::$handle;    }    

}

class Logger {

    static private $logger = NULL;

    static function logIt($it) {        $dbc = DbConnection::connect();        if(self::$instance == NULL) {             self::$instance = new Logger);        }    }

    private function __construct() {}

}

Happy hacking…

{ 2 comments }

I teach PHP, Perl, and Ruby at CCSF, and every semester I hear some wild statements from students. Since most of my students are adults with degrees from prestigious universities, and many of them have achieved some success in fields unrelated to programming, they seem to think that their expertise in project management, or web design entitles them to easy success in an introductory programming course. Here are some of the things I hear.

  1. “My multimedia instructor told me that PHP will be easy to learn since I’m an HTML and CSS maven.”
  2. “I’m a Dreamweaver professional, so I’m sure PHP will be a no-brainer for me.”
  3. “My roommate works at Yahoo. I hear her talking to her friends about programming and I’ve picked up PHP by osmosis.”
  4. “I took a C course 20 years-ago, but I never use it. Anyway, I’m sure I’ll be fine with PHP.”
  5. “PHP is just shell scripting, so I’ll do the assignments using shell.”
  6. “I have a CS degree. I can write a compiler in assembler. I’ve programmed mainframes and I know 20 languages, including ALGOL and LISP. I can learn PHP in my sleep. Just one question, what is this HTML stuff?”
  7. “I’m going to build a website like YouTube or Google. I want to use PHP or Java. Which one should I learn?”
  8. “I don’t know anything about programming, but I’m very smart. And I work very hard. There shouldn’t be any problem. What is HTML  again?”

My favorite way of learning anything new is definitely #3: osmosis. It rocks.

Keep hacking…

{ 3 comments }

The Registry Design Pattern in PHP

by doug on December 25, 2009

in PHP

The Registry design pattern gives us a way to overcome scoping complexities in your object-oriented programs. In this post I want to talk about how we use a Registry class in the MojoMVC.

PHP Scope: Main, Class, and Method

Though my diagram looks like the interior of a single-celled animal, I mean to suggest that the attributes inside classes are encapsulated within impermeable walls. And that classes are impermeable to the global variables in Main. This is a good thing in OOP Land.

In the MojoMVC, every request requires a Request object. There are times when other objects need that information. PHP has global variables by default, with local variables inside regular functions, and public, protected, and private methods inside classes. Since we don’t speak Kludge here, we need a another strategy for passing information around. The Registry pattern fills the bill.

We use the Registry class to take advantge the fact that classes have super global visibility—they can walk through walls like the super global variables ($_GET, $_POST, etc), functions, and constants. In other words, our Registry class can function as a super global delivery messenger as long as we give it some static setters and getters.

The Registry Class

1    class Registry extends Base {
2       static private $data = array();
3
4       private function __construct() {}
5
6       static public function get($key)
7       {
8          return self::$data[$key];
9       }
10
11       static public function set($key,$value)
12       {
13          self::$data[$key] = $value;
14       }
15    }

We can use it like this:

Registry::set(’string’, ‘this is the name’);
print Registry::get(’string’);  // output: this is the name

class NextClass {
function __construct() {
print Registry::get(’string’);
}
}


$n = new NextClass;  // output: this is the name

Now we have a class that walks through walls to deliver the values stored inside it. All we have to do is store the Request object in the Registry, like this:

Registry::set(‘request’, $this->r);

You’re probably wondering where $this->r came from. That’s an interesting story, but it will have to wait until next time.

For more information on the Registry pattern, check out your friendly Google.

{ 0 comments }

Creating a Textile Decorator Class

by doug on December 22, 2009

in PHP

I’m lazy when it comes to writing valid HTML. I know it’s the right thing to do, but I’ve developed some bad habits over the years. There are too many times when I forget quotes, alt tags, and ending tags. So I’ve decided to outsource my HTML generation to a machine: Textile.

Textile is a “human web text generator”. I like Textile because I can use simple formatting cues to generate any HTML you want. A simple example would be,

p. This is a paragraph. "A link to a URL":http://someurl

Textile will turn that text into this HTML:

<p>This is a paragraph. <a href="http://someurl">A link to a <spanclass="caps">URL</span></a></p>

In my CCSF courses I’ve developed a small PHP framework that I use as a teaching tool for my advanced PHP course. I call it MojoMVC. MojoMVC generates output of any kind by employing Decorator classes to format the output. The default format is HTML, but Decorators can be of any kind, including XML, PDF, images, and so on. All you have to do is write the class for the format you want. I created a HTMLDecorator class to have Textile ease my HTML woes.

MojoMVC Overview:

  1. MojoMVC is a conventional MVC framework that receives a request for the URL http://you.com/cs130a/syllabus.
  2. Controller classes are mapped to URLs.
  3. Which means, there is a cs130aController class and a syllabus page to be displayed.
  4. Every controller class has a render method defined in the parent class, ApplicationController.
  5. Every render method uses a Decorator class to format output.

The render in ApplicationController looks like this:

 1  class ApplicationController extends Base {
 2      // snip //
 3      function render() {
 4         // Default is HTMLDecorator
 5         $klass = $this->as.'Decorator';
 6         // Decorators all have a render()
 7         $decorator = new $klass;
 8         // Pass the current instance to the decorator for rendering.
 9         $decorator->render($this) ;
10         exit;
11      }
12  } 

By the way, one of PHP’s Good Parts in visible in this method—the easy implementation of polymorphism in lines 5, 7, and 9.

After we define the render method, the next step is to create a Decorator that will take the current instance and render its output using Textile. Here’s how it works.

The MojoMVC HTMLDecorator

 1 class HTMLDecorator
 2 {
 3
 4     function render($klass)
 5     {   // $klass is instance of current controller
 6         $textile = new Textile; // new Textile object
 7         // Check to make sure we have the requested object
 8         if (file_exists(VIEWS.$klass->r->controller.'/'.$klass->r->action.'.html'))
 9         {
10             // If so, run the method requested
11             if (method_exists($klass->r->controller.'Controller', $klass->r->action))
12             {
13                 $action = $klass->r->action;
14                 $klass->$action();
15             }
16             // Buffer output so we can pass it to Textile
17             ob_start();
18             include (VIEWS.$klass->r->controller.'/'.$klass->r->action.'.html');
19             // Textileize the HTML
20             $klass->out = $textile->textileThis(ob_get_clean());
21         } else
22         {
23             include (VIEWS.$klass->r->controller.'/'.$klass->r->error404.'.html');
24         }
25         // Include the layout HTML file that displays the requested page.
26         if (file_exists(LAYOUTS.$klass->r->controller.'.html'))
27         {
28             include LAYOUTS.$klass->r->controller.'.html';
29         } elseif (file_exists(LAYOUTS.'default.html'))
30         {
31             include LAYOUTS.'default.html';
32         } else
33         {
34             print $klass->out;
35         }
36     }
37 }

Most of this code is all about error checking. Textileizing is a matter of saving the output (using ob_start and ob_get_clean), loading Textile, creating an instance, and running the text through the textileThis method.

To learn more about Textile, check out the Textile home page. Textile has been ported to Ruby, where it is known as RedCloth.

For an easy-to-digest introduction to the Decorator design pattern, check out the Head First Design Patterns sample chapter.

Happy hacking…

{ 0 comments }

Have you noticed that your Drupal app feels sluggish? Here’s a visual map of the wheel-spinning Drupal goes through to say “Hello, World”. It’s impressive and depressing at the same time. Click on the image to see the whole story.

Part of the Very Big Picture

{ 0 comments }