Don't Start With A Blank Page

When creating a new Web page, use a prototype to lay out the file structure and implement common elements of the presentation. Using a template helps to insure the file format will be more readily grasped by new readers, and makes it easier to remember to include all of the necessary details.

Three prototype files are available in the/shared/incdirectory that should be used when constructing any new pages:

These three prototypes all usePageFrame.php(View Source)to build the overall HTML framework for the page. They are heavily commented with instructions for what needs to be placed where and how to customize them for a particular application. In the simplest case, setting the page title and adding some content is all that will be needed to create a new Web page. Additional code can be added as needed to create any level of complexity desired, yet still fit within the overall design framework of the MIT Sloan site

Separate Logic and Presentation

Avoid heavy logic within presentational code (HTML). While some processing and logic often needs to be done when it is nestled within a tag soup of HTML, avoid making in-page coding complex. One should not be doing more than basicforeach (),if (), and$obj->get*()within the presentation parts of the PHP document source

Use PHP To Disable HTML

When parts of an HTML page are [temporarily] disabled, they should be commented out using PHP rather than HTML comments: If the code is disabled by PHP, it will not be sent to the browser, reducing network traffic, and eliminating false "hits" by search engines.

In general, HTML comments should only be used to provide hidden information in the HTML source code that may be useful to debuggers and maintainers, such as the date the last time the page was edited.

<?php
define('LastModified','April 9, 2013 @ 5:29 pm'); 
/* 
 *    Copyright 2013 by MIT Sloan School of Management.  All rights reserved. 
 * 
 *    $Id: /path/to/page.php,v $ 
 */ ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
<head> 
    <title><?php echo $pagetitle ?> - MIT Sloan</title> 
</head> 
<body> 

<ul> 
<?php // INCORRECT:    // this gets sent to the browser ?> 
    <!--<li>November 1, 2012 
    <br/> 
    <a href="mapsearch=Wong+Auditorium">Wong Auditorium</a>, 12 Noon<br/> 
    Light lunch, 11:30am.</li>--> 
<?php // CORRECT:    // this stays on the server ?> 
<?php /* 
    <li>November 1, 2012 
    <br/> 
    <a href="mapsearch=Wong+Auditorium">Wong Auditorium</a>, 12 Noon<br/> 
    Light lunch, 11:30am.</li> 
*/ ?> 
</ul> 

<?php // CORRECT: maintenance documentation ?> 
<!-- <?php echo LastModified ?> --> 
</body> 
</html> 
<?php 
// 
// EOF: page.php

Return Early

To enhance readability of functions and methods, it is wise to return early if simple conditions apply that can be checked at the beginning of a method: It's better to return early, keeping indentation and the brain power needed to follow the code lower.


<?php
// INCORRECT:    // simple handler gets lost, more indentation
function foo($bar,$baz) 
{ 
    if ($GLOBALS['foo']) 
    { 
        //assume 
        //that 
        //here 
        //is 
        //the 
        //whole 
        //logic 
        //of 
        //this 
        //method 
        return $calculated_value; 
    } 
    else return null; 
} 
?>
<?php
// CORRECT:    // simple handler is obvious, cleaner code
function foo($bar,$baz) 
{ 
    if (!$GLOBALS['foo']) 
        return null; 

    //assume 
    //that 
    //here 
    //is 
    //the 
    //whole 
    //logic 
    //of 
    //this 
    //method 
    return $calculated_value; 
}

Split Long Statements

Split long if statements

Longifstatements may be split onto several lines when the number of character per line limit would be exceeded. The condition clauses are moved to following line(s), indented one tab. Logical operators (&&,||, etc.) should be aligned under the opening clause to make it easier to comment (and exclude) the condition. When splitting statements this way, the closing parenthesis may be on its own line, positioned under the opening parenthesis. The opening brace for the conditional code goes on the next line, aligned with the start of the statement.

Keeping the operators at the beginning of the line has two advantages: It is trivial to comment out a particular line during development while keeping syntactically correct code (except for the first line). It also keeps the logic at the front of the code where it's more readily observed. Scanning such conditions is very easy since they are aligned below each other.

<?php
if ((  $condition1 
    || $condition2 
    ) 
&&  $condition3 
&&  $condition4 
   ) 
{ 
    //code here 
}

The first condition may be aligned to the others.

<?php
if ($condition1 
||  $condition2 
||  $condition3)   // closing parenthesis on the last clause's line is OK 
{ 
    //code here 
}

When anifstatement is really long enough to be split, it might be better to simplify it. In such cases, you could express conditions as variables and compare them in theifstatement. This yields "naming" and splitting the condition sets into smaller, better understandable chunks. The disadvantage in doing so is the increased processing overhead needed to create the additional variables, which should be avoided within loops.

<?php
$is_foo=($condition1 || $condition2); 
$is_bar=($condition3 && $condtion4); 
if ($is_foo && $is_bar) 
{ 
    // .... 
}

Ternary operators

The same rule as forifstatements also applies for the ternary operator: It may be split onto several lines, keeping the question mark and the colon at the front.

<?php
$a = $condition1 && $condition2 
    ? $foo : $bar; 
$b = $condition3 && $condition4 
    ? $foo_man_this_is_too_long_what_should_i_do 
    : $bar;

Split function call on several lines

The style guide permits a maximum line length of 80 characters. When calling functions or methods with many parameters it may be impossible to respect the line limit. In that case, splitting the function calls between parameters is needed

Several parameters per line are allowed, filling the line as much as possible. Subsequent parameter lines need to be indented one tab compared to the level of the function call. If there is room for one or more parameters on the function call line, the opening parenthesis is between the function name and parameter name as usual. The closing parenthesis then immediately follows the last parameter:

<?php
$this->someObject->subObject->callThisFunctionWithALongName($parameterOne, 
    $parameterTwo,$aVeryLongParameterThree);

If the function call and the first parameter will not fit on the same line, the opening parenthesis is aligned with the function call on the next line, followed by a tab and the first parameter. Subsequent parameters can be used to fill the rest of the line, or can be specified on following lines, indented to fall under the first parameter. The closing parenthesis then goes on a line after the last parameter, aligned with the opening parenthesis.

The same applies not only for parameter variables, but also for nested function calls and for arrays.

<?php
$this->someObject->subObject->callThisFunctionWithALongName 
(   $this->someOtherFunc 
    (   $this->someEvenOtherFunc 
        (   'Help me!', 
            array('foo' =>'bar', 
                  'spam'=>'eggs'), 
            23 
        ), 
        $this->someEvenOtherFunc() 
    ), 
    $this->wowowowowow(12) 
);

Nesting those function parameters is allowed if it helps to make the code more readable, not only when it is necessary when the characters per line limit is reached.

Using fluent application programming interfaces often leads to many concatenated function calls. Those calls may be split onto several lines. When doing this, all subsequent lines are indented by one tab and begin with the->arrow.

<?php
$someObject->someFunction('some','parameter') 
    ->someOtherFunc(23,42) 
    ->andAThirdFunction();

Split long assigments

Assigments may be split onto several lines when the character/line limit would be exceeded. The equal sign has to be positioned onto the following line, and indented by one tab.

<?php
$GLOBALS['TSFE']->additionalHeaderData[$this->strApplicationName] 
    = $this->xajax->getJavascript(t3lib_extMgm::siteRelPath('nr_xajax'));

Code Efficiently

PHP is used as an interpreted language, rather than a compiled one. Each time a page loads, the source file(s) has/have to be read from disk, parsed, reduced to bytecodes, and interpreted by the Zend engine. Modern operating systems cache disk accesses, and using a bytecode cache with enough memory allocated to its buffers can nearly eliminate the necessity of parsing source files once active development is finished. Between the disk and bytecode caches, PHP code can be just as fast as, or even faster than, compiled languages which run on a virtual machine, such as Java. There are no optimizations, however, which can make up for sloppy, inefficient programming: It's up to you, the developer, to be wary of practices that lead to slower page loads and higher processing requirements.

You should always useechorather thanprintbecause it is more flexible and doesn't have the overhead of returning a value. (printalwaysreturns1, so its return value isn't terribly useful in the first place.)

Don't callechorepeatedly, use string concatenation instead to eliminate the overhead of multiple function calls: Neitherechonorprintautomatically emit a newline at the end of the string(s) they are passed, so there is absolutely no advantage to having multiple calls in a row.

<?php
// INCORRECT:   // prints "thisisreallybad! 
echo 'this';    // no whitespace in any of these statements 
echo 'is'; 
echo 'really'; 
echo 'bad!'; 

// CORRECT:     // prints "This is much cleaner." 
echo 'This '    // spaces embedded in each source string 
    .'is ' 
    .'much ' 
    .'cleaner.';

Create variables used to store "constant" values (ones which do not change with each iteration) before beginning loops. Otherwise, the variable will be created and destroyed during each loop iteration, which can be averyexpensive bit of overhead.

Object oriented vs. procedural code

Obejct oriented programming seeks to deal with systems and data as objects that interact with each other by passing messages through interfaces. Conceptually it's an attractive programming model because the boundaries between objects are well defined, making it easier to keep track of who owns what and how things can be manipulated. With that surface simplicity, however, comes the burden of increased processing overhead, and, behind the scenes, a much more complex system to support the programming model.

While lean classes can be constructed that provide only the necessary methods for the data they are encapsulating, many classes are built with all sorts of bells and whistles "in case" somebody needs them. There are even style guides suggesting that public properties should not be used and class data members have to be read and written usinggettorsandsettors. One problem with writing Web code that way is every time a Web page is loaded, the entire class [file] has to be read and parsed, even if only a small part of the class functionality is being used. On a busy Web server, the extra overhead can add up quickly. Another problem, caused by only having one class per file, is pages that need functionality out of lots of classes will need to open and parse lots of files, which adds to congestion on the server's disk access bus.

Procedural code, on the other hand, requires a more intimate understanding of the data and logic for an application, resulting in an apparently more complex system design. The resulting code is more easily tuned for performance, though, and can be pared down to the minimum required to do the job without a major effort. As a result, pages load faster with smaller server requirements, and they don't have to carry around unused code the way OOP classes often do.

There are many cases where PHP classes are the most logical way to deal with a data set: Having an array of class objects representing data records makes it easy to present the data uniformly - aforeachloop can iterate over the array, calling the same method for each object to write the data to the browser. That makes the body of the loop a single statement, rather than a mass of mingled PHP and HTML that is more easily understood in a class method where the related variables are close at hand for reference. A balance can be found between design and implementation simplicity, but for the best performance, keep in mind that smaller files require less processing power, and will have lower communication overhead, even if the reduction is only internal to the server.

Reduce Duplicate Code

Duplicated code isA REALLY BAD THING™: Multiple copies of the same code require (approaching exponentially) more effort to debug or update, duplicated code increases the size of files, having repeated copies of the same thing (with the names changed or not) makes the code harder to comprehend, and when changes are introduced, verifying the correctness of the code set becomes "rather" difficult.

Copy-paste-edit developmentis the cause of most code duplication, often the result of an "add another element to my list" request: An existing list item is copied, pasted in above or below the original, then modified with the different information for the new item. While this procedure will add one item with a minimum of immediate effort, it makes changing the presentation of the data in the list effectively impossible unless an unreasonable amount of effort is expended. In addition, if editing accidentally removes characters from HTML tags - or even removes the tags altogether - fixing the resulting problems will most likely take a significant amount of time.

Avoid copy-paste-edit development as though it were poison ivy!If you need to duplicate some existing HTML code, look at the similarities and differences between the two instances. Write a PHP function (use the language to do what it was designed for) to emit the common elements, and pass parameters to control introduction of the differences. In all but the most trivial cases, the result will be a smaller file that is easier to maintain. Smaller files require less processing and often have lower communication overhead.

While the code in the left column of the illustration below appears to be about the same size as the code in the right column, there are a couple of problems:

  • This is only three copies of the same code. The file where it was derived from has over sixty similar code blocks and is expected to continue to grow. It is already much larger than it would be if it were written using a function definition and calls.
  • The code is already more difficult to maintain. If, for example, the image class attribute needed to be changed from headshot to bio-thumb , it would have to be corrected in three places in this subset example vs. once in the right column.
<?php
// INCORRECT:    // copy, paste, edit 
<div class="bioblurbs" id="john-doe"> 
    <img src="/images/johndoe.jpg" alt="" class="headshot" /> 
    <!-- remove no-image class when photo is added --> 
    <div class="infoblock"> 
        <h3>John Doe</h3> 
        <p>Co-founder &amp; CEO, John Doe Company<br/> 
            April 12, 2013<br/> 
            <a href="mapsearch=Wong+Auditorium">Wong Auditorium</a>,
            12 Noon</p> 
        <p>John Doe will speak about doing great stuff.</p> 
        <p><a href="/pdf/johndoe.pdf">Full bio &gt;&gt;</a> (PDF)</p> 
    </div> 
</div> 

<div class="bioblurbs" id="jane-smith"> 
    <img src="/images/janesmith.jpg" alt="" class="headshot" /> 
    <!-- remove no-image class when photo is added --> 
    <div class="infoblock"> 
        <h3>Jane Smith</h3> 
        <p>President and CEO, Company, Inc.<br/> 
            March 7, 2013<br/> 
            <a href="mapsearch=Wong+Auditorium">Wong Auditorium</a>,
            12 Noon<br/> 
            Light lunch, 11:30am</p> 
        <p>Jane Smith speaks about helping Company grow.</p> 
        <p><a href="/pdf/janesmith.pdf">Full bio &gt;&gt;</a> (PDF)</p> 
    </div> 
</div> 

<div class="bioblurbs" id="joe-doe"> 
    <img src="/images/joedoe.jpg" alt="" class="headshot" /> 
    <!-- remove no-image class when photo is added --> 
    <div class="infoblock"> 
        <h3>Joe Doe</h3> 
        <p>President, Megagiant Corp.<br/> 
            January 23, 2013<br/> 
            <a href="mapsearch=Wong+Auditorium">Wong Auditorium</a>,
            12 Noon<br/> 
            Light lunch, 11:30am</p> 
        <p>Joe Doe tells it like it is.</p> 
    </div> 
</div>
<?php
// CORRECT: 
function bioBlurb($name,$bio,$date,$where,$when, 
        $program,$img='',$bioURL='') 
{   $id=str_replace(' ','-',$name); 
    $url='mapsearch='.urlencode($where); 
    ?> 
<div class="bioblurbs" id="<?php echo $id ?>"> 
<?php if ($img) 
    { ?> 
    <img src="/images/<?php echo $img ?>" alt="<?php 
        echo $name."'s picture"?>" class="headshot" /> 
<?php 
    } ?> 
    <div class="infoblock <?php if (!$img) echo ' no-image' ?>"> 
        <h3><?php echo $name ?></h3> 
        <p><?php echo $bio ?><br/> 
            <?php /* intentional indent */ echo $date ?><br/> 
            <a href="<?php echo $url ?>" rel="external"><?php 
    echo $where ?></a>, <?php echo $when ?></p> 
        <p><?php echo $program ?></p> 
<?php if ($img) 
    { ?> 
        <p><a href="/pdf/<?php 
        echo $bioURL.pdf ?>">Full bio &gt;&gt;</a> (PDF)</p> 
<?php 
    } ?> 
    </div> 
</div> 
<?php 
} 

bioBlurb('John Doe','Co-founder &amp; CEO, John Doe Company', 
         'April 12, 2013','Wong Auditorium','12 Noon', 
         'John Doe will speak about doing great stuff.', 
         'johndoe.jpg','johndoe'); 
bioBlurb('Jane Smith','President and CEO, Company, Inc.',
         'March 7, 2013','Wong Auditorium', 
         '12 Noon<br/>Light lunch, 11:30am', 
         'Jane Smith speak about helping Company grow.', 
         'janesmith.jpg','janesmith'); 
bioBlurb('Joe Doe','President, Megagiant Corp.', 
         'January 23, 2013','Wong Auditorium', 
         '12 Noon<br/>Light lunch, 11:30am', 
         'Joe Doe tells it like it is.', 
         'joedoe.jpg',/* no bio PDF! 'joedoe' */);

When building a list such as the one illustrated above, consider the question "what's the data source?" If the information is coming from a database query or an XML feed, the display function can probably be written such that it's fed a record directly from the data source, and building the list becomes nothing more than a foreachthat repeatedly calls the function, passing the data records in succession:

<?php
require_once $_SERVER['DOCUMENT_ROOT'].'/path/to/data-source.php'; 

$Faculty=GetFacultyInGroup($groupName); 

/** 
* displays the faculty member's name as a link to their profile 
* 
* @param array $person, database record with info about the faculty member 
*/ 
function ShowFaculty($person) 
{ ?> 
    <li><a href="/faculty/profile.php?id=<?php 
    echo $person['PERSONID']?>"><?php 
    echo $person['FULLNAME']?></a></li> 
<?php 
} 
?> 
<h3>Our Staff</h3> 
<ul> 
<?php foreach ($Faculty as $person) ShowFaculty($person) ?> 
</ul>

Use existing functions when possible

Don't reinvent the wheel. In addition to the extensive library of functions built into PHP, a significant number of routines have been written by other members of the team. There are files of functions that can be used in the/shared/incdirectory, and other places on the server. As you find or write other code that is useful in more than just your current project, encapsulate it in a well-documented function (or class, if it's a more complex set of data and operations) and either add it to one of the existing files containing similar functionality, or create a new one with a name describing the type of code to be found inside (almost always required when writing a new class). Building and using such a code library not only reduces the effort to build new applications, but it makes debugging and maintaining the entire code base much more efficient: Rather than having to track down an ill-defined set of copies of similar code if an error is detected, having a common code base meansonefix can update a host of applications with the correction.

Validation

Always remember the cardinal rule of network security:Data coming from userland cannot be trusted.Even if you build a form that limits line lengths, data values, and uses Javascript to insure only valid data can get to the server when the submit button is pressed, there's nothing to stop Joe Hacker from creating a form that connects to your script and sends you a load of bull. Even if it's not Joe, it could be a glitch on the network, or any of a host of other problems that could corrupt the data -it can't be trusted. As a result,YOU MUST ALWAYS VALIDATE DATA ON THE SERVERbefore using it or passing it to a database (or any other trusting application) if it came from userland - form submittals, email messages, tweets, etc.

There are two basic types of data errors that need to be protected against -invaliddata, andincorrectdata.

Invalid data includes things such as strings that are longer than themaxlengthattribute on an<input>field allows, or values that cannot be chosen from a<select>list. A successful submission of a valid form will not result in receipt of invalid data, so if it is detected, all of the data received must be discarded, and displaying nothing more than a terseInvalid datamessage is an appropriate response. (Don't betooharsh, though - the invalid datacouldbe the result of a network error.)

Incorrect data, on the other hand, is a common occurrence: Users type their passwords with the CapsLock key on, or enter an email address in a telephone number field, etc. In such cases, the job of the validation code is to detect as many of these types of errors as possible and cause an appropriate error message to be displayed so the user can intelligently correct the problem. When incorrect data is detected, be nice - the error message is supposed to help the user, not belittle them. Don't spend forever trying to make a foolproof system, though, because fools are too ingenious. Besides, only a fool will [be likely to] use a foolproof system...

results matching ""

    No results matching ""