Skip to content

Instantly share code, notes, and snippets.

@nikic
Created July 29, 2012 14:21
Show Gist options
  • Star 24 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nikic/3199208 to your computer and use it in GitHub Desktop.
Save nikic/3199208 to your computer and use it in GitHub Desktop.
Quick doesn't have to mean dirty: Also applies to PHP!

Quick doesn't have to mean dirty: Also applies to PHP!

This is just a quick response to http://me.veekun.com/blog/2012/07/28/quick-doesnt-mean-dirty/. I won't bother to write a proper blog post for this, so a Gist will have to do ;)

When I read that article, one thing really striked me: If you want to quickly create a web app in PHP, you do exactly the same. I mean, exactly.

I never used the Silex microframework before, so I took this as a chance to see how it works. I'll just do the same as eevee did, only with a bit less commentary (this is a Gist after all!)

I hope that this will show you that PHP and Python are really similar to work with. Also this should show that just because you're using PHP, doesn't mean that you write dirty code. The similarity in the process and code is really incredible :)

Creating a guestbook using Silex

First create the project:

curl -s https://getcomposer.org/installer | php
php composer.phar create-project fabpot/silex-skeleton guestbook
cd guestbook/

Run php -S localhost:8888 -t web/ to start the webserver. You'll find a friendly Hello World message if you visit localhost:8888/index_dev.php in your browser.

Then create a git repo:

rm -rf .git
git init
git add -A
git commit -m "Initial commit"

There are already two templates in the templates/ folder, we just modify them a bit to match eevee's code:

vim templates/layout.html
<!DOCTYPE html>
<html>
    <head>
        <title>{% block title '' %} - My Awesome Site</title>

        <link href="{{ app.request.basepath }}/css/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <section id="content">
            {% block content %}{% endblock %}
        </section>
        <footer id="footer">
            My awesome guestbook
        </footer>
    </body>
</html>
vim index.html
{% extends "layout.html" %}

{% block title %}Guestbook{% endblock %}

{% block content %}
    <h1>Guestbook</h1>

    <p>Welcome to my guestbook!</p>

    <ul class="guests">
        <li>...</li>
    </ul>
{% endblock %}

That doesn't give us much yet, we need to create some kind of database. To save me the installation of mysql I'll use sqlite:

vim src/app.php (addition)
<?php
$app['db'] = $app->share(function() {
    $pdo = new PDO('sqlite:' . __DIR__ . '/../db.sq3');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    return $pdo;
});

Also create a console task to create the table structure (there is already a skeleton in the file, so I don't even have to look at docs):

vim src/console.php (change)
<?php
$console
    ->register('create-db')
    ->setDescription('Create database tables')
    ->setCode(function (InputInterface $input, OutputInterface $output) use ($app) {
        $app['db']->query(
            "CREATE TABLE guestbook (
                 id INTEGER PRIMARY KEY AUTOINCREMENT,
                 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                 name TEXT, message TEXT 
             );
             CREATE INDEX timestamp_index ON guestbook (timestamp);"
        );

        $output->writeln('Created database!');
    })
;

Now we can create the DB using ./console create-db.

Oh, and yeah, I hate ORMs, I prefer raw SQL.

Next let's modify the template to actually display something:

vim templates/index.html (change)
<ul class="guests">
    {% for entry in entries %}
        <li>
            <blockquote>{{ entry.message }}</blockquote>
            <p> —<cite>{{ entry.name }}</cite>, <time>{{ entry.timestamp }}</time></p>
        </li>
    {% endfor %}
</ul>

And adjust the controller for this:

vim src/app.php
<?php
$app->get('/', function () use ($app) {
    return $app['twig']->render('index.html', array(
        'entries' => $app['db']->query(
            'SELECT * FROM guestbook ORDER BY timestamp DESC'
        )
    ));
})

Finally, let's add the code for adding new guestbook entries:

vim templates/index.html
<hr>

<form action="" method="POST">
    <p>Name: <input type="text" name="name"></p>
    <p>Message: <textarea name="message" rows="10" cols="40"></textarea></p>
    <p><button>Sign</button></p>
</form>
vim src/controllers.php
<?php
$app->post('/', function (Request $req) use ($app) {
    $app['db']->prepare(
        'INSERT INTO guestbook (name, message) VALUES (?, ?)'
    )->execute(array(
        $req->request->get('name')    ?: 'Some dummy who forgot to leave a name',
        $req->request->get('message') ?: 'WOW THIS IS THE BEST WEBSITE EVER',
    ));

    return $app->redirect('/');
});

Again, you can see the page using the php -S localhost:8888 -t web/ webserver. It is safe against XSS and SQLi, just like the Python code (the template engine does automatic escaping and we used prepared statements).

I won't bother with deployment here. You could obviously just deploy to Heroku, exactly as you did with Python. Or just upload it to some freespace via FTP. Whatever.

=====

Thanks for listening,
~nikic (http://nikic.github.com/, https://twitter.com/nikita_ppv)

@marioawad
Copy link

My response to anyone criticizing PHP is simple. Give me a CMF (Content Management Framework) that is remotely close to what Drupal provides... and then we can talk :-)

@damilare
Copy link

@nikic I am using php 5.3, this should be modern enough. Btw, if I install 5.4, how easy will it be for me to switch between versions, for various projects?

@klaussilveira I have used ZF, Symfony, and other PHP frameworks. Most of them lift concepts from other languages/frameworks, so they don't fit perfectly. There is simply no "unity of design" in the language, you have to do a lot of context switching writing in one language. Its a productivity killer, well for people who look for fun in what they do.

@marioawad, a programming language is not a CMF, and a CMF is not the only thing you do with programming languages. I'd achieve anything you would do in Drupal with Django and in a lot lesser lines of code, thus making it more readable and maintainable.

@marioawad
Copy link

@damilare definitely a programming language is not a CMF but the availability of a well-designed and popular CMF built on top of that particular language is a huge advantage. As least for me and my company. I'm afraid I'll have to disagree that with Django you can achieve anything I'd build with Drupal with less lines of Code. If we're building a website with different content types (services, sub-services, clients using those services, projects stating which services they were built upon...) then Drupal is the tool of choice, and you can't beat it for this particular use case. If we're building an online accounting system, then definitely Django is better suited, and for us PHP developers, then maybe we'd look at Zend Framework, Symfony, Code Igniter, CakePHP, ...

@damilare
Copy link

@marioawad

You'd still do it with a lot less code. Django has a concept of Content Type which is more abstract and powerful than what Drupal offers. https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/

@damilare
Copy link

@bitdagger

Good to know php now has an inbuilt web server, out of curiosity, is this a production ready feature?

Update: http://php.net/manual/en/features.commandline.webserver.php

@damilare
Copy link

@bitdagger

I am with your sysadmin on this one :)

@marioawad
Copy link

@damilare having content types is one of the needed features to build such websites. I'm curious about Django CMS (cause it seams more appropriate to compare Drupal with Django CMS rather than plain Django), are you using Django CMS? or do you prefer to deliver website solutions on Django only? thank you for your input.

@damilare
Copy link

@marioawad

I would compare Wordpress to Django CMS and sort of compare Drupal with Django in a poor man's sense. Reason being that, Django ships with an Admin interface you can give your clients, while you still have the power and flexibility of Django modules to change the underlying business logic. With Django CMS, the conventions quite stricter.

I'd say spend some time with Django and play around, its easier to churn out all sorts of applications from websites to "enterprise" systems with little efforts and the power of a very good programming language.

@marioawad
Copy link

@damilare thanks again for your input. I'd love to see what can be accomplished and have a sense of the available dev tools so that I compare with what I already have. Any recommendations?

@damilare
Copy link

@marioaward

https://www.djangoproject.com/ is very resourceful. You can also ask questions on #django @ freenode

@marioawad
Copy link

@damilare thanks a lot. Do take a look at Drupal 8 and Symfony 2 framework whenever you have time too. Cheers.

Copy link

ghost commented Aug 1, 2012

I think that the point of the article was "Yeah, you like PHP because it's quick to set up? Well, Python can be as quick without being as dirty as PHP". And now, this rebuttal is... "But look, I can be as quick as your Python example with PHP!"? Huh? Didn't we lose something along the way here?

@jacketsy
Copy link

On the one hand is to provide powerful guarantee in moral, legal, and not weak, http://www.endlesssummertanninglp.com/

@jacketsy
Copy link

such as to the cost of living; http://www.secondnaturecanvas.com/ On the other hand is to implement on system design Throughout the urban and rural fair And reduce the left-behind children such a large group. Three is about the whole social moral belief of landslide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment