phpFashion

Na navigaci | Klávesové zkratky

Is Singleton Evil?

Singleton is one of the most popular design patterns. Its purpose is to ensure the existence of only one instance of a certain class while also providing global access to it. Here is a brief example for completeness:

class Database
{
    private static $instance;

    private function __construct()
    {}

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

    ...
}

// singleton is globally accessible
$result = Database::getInstance()->query('...');

Typical features include:

  • A private constructor, preventing the creation of an instance outside the class
  • A static property $instance where the unique instance is stored
  • A static method getInstance(), which provides access to the instance and creates it on the first call (lazy loading)

Simple and easy to understand code that solves two problems of object-oriented programming. Yet, in dibi or Nette Framework, you won’t find any singletons. Why?

Apparent Uniqueness

Let's look closely at the code – does it really ensure only one instance exists? I’m afraid not:

$dolly = clone Database::getInstance();

// or
$dolly = unserialize(serialize(Database::getInstance()));

// or
class Dolly extends Database {}
$dolly = Dolly::getInstance();

There is a defense against this:

final public static function getInstance()
{
    // final getInstance
}

final public function __clone()
{
    throw new Exception('Clone is not allowed');
}

final public function __wakeup()
{
    throw new Exception('Unserialization is not allowed');
}

The simplicity of implementing a singleton is gone. Worse – with every additional singleton, we repeat the same piece of code. Moreover, the class suddenly fulfills two completely different tasks: besides its original purpose, it takes care of being quite single. Both are warning signals that something is not right and the code deserves refactoring. Bear with me, I’ll get back to this soon.

Global = Ugly?

Singletons provide a global access point to objects. There is no need to constantly pass the reference around. However, critics argue that such a technique is no different from using global variables, and those are pure evil.

(If a method works with an object that was explicitly passed to it, either as a parameter or as an object variable, I call it “wired connection”. If it works with an object obtained through a global point (e.g., through a singleton), I call it “wireless connection”. Quite a nice analogy, right?)

Critics are wrong in one respect – there is nothing inherently bad about “global”. It’s important to realize that the name of each class and method is nothing more than a global identifier. There is no fundamental difference between the trouble-free construction $obj = new MyClass and the criticized $obj = MyClass::getInstance(). This is even less significant in dynamic languages like PHP, where you can “write in PHP 5.3” $obj = $class::getInstance().

However, what can cause headaches are:

  1. Hidden dependencies on global variables
  2. Unexpected use of “wireless connections”, which are not apparent from the API of classes (see Singletons are Pathological Liars)

The first issue can be eliminated if singletons do not act like global variables, but rather as global functions or services. Consider google.com – a nice example of a singleton as a global service. There is one instance (a physical server farm somewhere in the USA) globally accessible through the identifier www.google.com. (Even clone www.google.com does not work, as Microsoft discovered, they have it figured out.) Importantly, this service does not have hidden dependencies typical for global variables – it returns responses without unexpected connections to what someone else searched for moments ago. On the other hand, the seemingly inconspicuous function strtok suffers from a serious dependency on a global variable, and its use can lead to very hard-to-detect errors. In other words – the problem is not “globality”, but design.

The second point is purely a matter of code design. It is not wrong to use a “wireless connection” and access a global service, the mistake is doing it unexpectedly. A programmer should know exactly which object uses which class. A relatively clean solution is to have a variable in the object referring to the service object, which initializes to the global service unless the programmer decides otherwise (the convention over configuration technique).

Uniqueness May Be Harmful

Singletons come with a problem that we encounter no later than when testing code. And that is the need to substitute a different, test object. Let's return to Google as an exemplary singleton. We want to test an application that uses it, but after a few hundred tests, Google starts protesting We're sorry… and where are we? We are somewhere. The solution is to substitute a fictitious (mock) service under the identifier www.google.com. We need to modify the hosts file – but (back from the analogy to the world of OOP) how to achieve this with singletons?

One option is to implement a static method setInstance($mockObj). But oops! What exactly do you want to pass to that method when no other instance, other than that one and only, exists?

Any attempt to answer this question inevitably leads to the breakdown of everything that makes a singleton a singleton.

If we remove the restrictions on the existence of only one instance, the singleton stops being single and we are only addressing the need for a global repository. Then the question arises, why repeat the same method getInstance() in the code and not move it to an extra class, into some global registry?

Or we maintain the restrictions, only replacing the class identifier with an interface (DatabaseIDatabase), which raises the problem of the impossibility to implement IDatabase::getInstance() and the solution again is a global registry.

A few paragraphs above, I promised to return to the issue of repetitive code in all singletons and possible refactoring. As you can see, the problem has resolved itself. The singleton has died.

16 years ago v rubrice PHP


Twitter for PHP

Twitter for PHP is a very small and easy-to-use library for sending messages to Twitter and receiving status updates with OAuth support.

Download Twitter for PHP 3.5

It requires PHP (version 5 or newer) with CURL extension and is licensed under the New BSD License. You can obtain the latest version from our GitHub repository or install it via Composer:

php composer.phar require dg/twitter-php

Twitter requires SSL/TLS as of January 14th, 2014. Update to the last version.

Getting started

Sign in to the http://twitter.com and register an application from the http://dev.twitter.com/apps page. Remember
to never reveal your consumer secrets. Click on My Access Token link from the sidebar and retrieve your own access
token. Now you have consumer key, consumer secret, access token and access token secret.

Create object using application and request/access keys:

$twitter = new Twitter($consumerKey, $consumerSecret,
	$accessToken, $accessTokenSecret);

Posting

The send() method posts your status. The message must be encoded in UTF-8:

$twitter->send('I am fine today.');

You can append picture:

$twitter->send('This is my photo', $imageFile);

Displaying

The load() method returns the 20 most recent status updates posted in the last 24 hours by you:

$statuses = $twitter->load(Twitter::ME);

or posted by you and your friends:

$statuses = $twitter->load(Twitter::ME_AND_FRIENDS);

or most recent mentions for you:

$statuses = $twitter->load(Twitter::REPLIES);

Extracting the information from the channel is easy:

<ul>
<?php foreach ($statuses as $status): ?>
	<li><a href="http://twitter.com/<?= $status->user->screen_name ?>">
		<?= htmlspecialchars($status->user->name) ?></a>:

		<?= Twitter::clickable($status) ?>

		<small>at <?= date("j.n.Y H:m", strtotime($status->created_at)) ?></small>
	</li>
<?php endforeach ?>
</ul>

The static method Twitter::clickable() makes links in status clickable. In addition to regular links, it links @username to the user’s Twitter profile page and links hashtags to a Twitter search on that hashtag.

Searching

The search() method provides searching in twitter statuses:

$results = $twitter->search('#nette');

The returned result is a again array of statuses.

Error handling

All methods throw a TwitterException on error:

try {
	$statuses = $twitter->load(Twitter::ME);
} catch (TwitterException $e) {
	echo "Error: ", $e->getMessage();
}

Additional features

The authenticate() method tests if user credentials are valid:

if (!$twitter->authenticate()) {
	die('Invalid name or password');
}

Other commands

You can use all commands defined by Twitter API 1.1. For example GET statuses/retweets_of_me returns the array of most recent tweets authored by the authenticating user:

$statuses = $twitter->request('statuses/retweets_of_me', 'GET', array('count' => 20));

Finally, the Truth About XHTML and HTML

I recently participated in a discussion that reminded me (again) of the deeply entrenched myths regarding the differences between HTML and XHTML. The campaign for the formats with the letter “X” was accompanied by great emotions, which usually do not go hand in hand with a clear head. Although the enthusiasm has long since faded, a significant part of the professional community and authors still believe a number of misconceptions.

In this article, I will attempt to bury the biggest of these myths in the following way. This article will contain only facts. I will save my opinions and your comments for a second article.

In the text below, by HTML I mean the version HTML 4.01, and by XHTML I mean the version XHTML 1.0 Second Edition. For completeness, I add that HTML is an application of the SGML language, while XHTML is an application of the XML language.

Myth: HTML allows tag crossing

Not at all. Tag crossing is directly prohibited in SGML, and consequently in HTML. This fact is mentioned, for example, in the W3C recommendation: “…overlapping is illegal in SGML…”. All these markup languages perceive the document as a tree structure, and therefore it is not possible to cross tags.

I am also responding to a reformulation of the myth: “The advantage of XHTML is the prohibition of crossing tags.” This is not the case; tags cannot be crossed in any existing version of HTML or XHTML.

Myth: XHTML banned presentation elements and introduced CSS

Not at all. XHTML contains the same sort of elements as HTML 4.01. This is mentioned right in the first paragraph of the XHTML specification: “The meaning of elements and their attributes is defined in the W3C recommendation for HTML 4.” From this perspective, there is no difference between XHTML and HTML.

Some elements and attributes were deprecated already in HTML 4.01. Presentation elements are forbidden in favor of CSS, which also answers the second part of the myth: the arrival of cascading styles with XHTML is unrelated, having occurred earlier.

Myth: HTML parser must guess tag endings

Not at all. In HTML, for a defined group of elements, the ending or starting tag can optionally be omitted. This is for elements where omitting the tag cannot cause ambiguity. As an example, take the ending tag for the p element. Since the standard states that a paragraph cannot be inside another paragraph, it is clear by writing…

<p>....
<p>....

…that by opening the second paragraph, the first must close. Therefore, stating the ending tag is redundant. However, for example, the div element can be nested within itself, so both the starting and ending tags are required.

Myth: HTML attribute notation is ambiguous

Not at all. XHTML always requires enclosing attribute values in quotes or apostrophes. HTML also requires this, except if the value consists of an alphanumeric string. For completeness, I add that even in these cases, the specification recommends using quotes.

Thus, in HTML it is permissible to write <textarea cols=20 rows=30>, which is formally as unambiguous as <textarea cols="20" rows="30">. If the value contained multiple words, HTML insists on using quotes.

Myth: HTML document is ambiguous

Not at all. The reasons given for ambiguity are either the possibility of crossing tags, ambiguity in writing attributes without quotes, which are already debunked myths, or also the possibility of omitting some tags. Here I repeat that the group of elements where tags can be omitted is chosen so as to omit only redundant information.

Thus, an HTML document is always unambiguously determined.

Myth: Only in XHTML is the ‘&’ character written as ‘&’

Not at all – it must also be written that way in HTML. For both languages, the characters < and & have a specific meaning. The first opens a tag and the second an entity. To prevent them from being understood in their meta-meaning, they must be written as an entity. Thus also in HTML, as stated by the specification.

Myth: HTML allows ‘messes’ that would not pass in XHTML

Not at all. This view is rooted in a series of myths that I have already refuted above. I haven't yet mentioned that XHTML, unlike HTML, is case sensitive for element and attribute names. However, this is a completely legitimate feature of the language. In this way, Visual Basic differs from C#, and it cannot objectively be said that one or the other approach is worse. HTML code can be made confusing by inappropriately mixing upper and lower case (<tAbLe>), XML code can also be confusing by using strings like id, ID, Id for different attributes.

The clarity of the notation in no way relates to the choice of one language over the other.

Myth: Parsing XHTML is much easier

Not at all. Comparing them would be subjective and therefore has no place in this article, but objectively, there is no reason why one parser should have a significantly easier time. Each has its own set of challenges.

Parsing HTML is conditioned by the fact that the parser must know the document type definition. The first reason is the existence of optional tags. Although their addition is unambiguous (see above) and algorithmically easy to handle, the parser must know the respective definition. The second reason concerns empty elements. That an element is empty is known to the parser only from the definition.

Parsing XHTML is complicated by the fact that the document can (unlike HTML) contain an internal subset DTD with the definition of its own entities (see example). I add that an “entity” does not have to represent a single character, but any lengthy segment of XHTML code (possibly containing further entities). Without processing the DTD and verifying its correctness, we cannot talk about parsing XHTML. Furthermore, syntactically, DTD is essentially the opposite of XML language.

In summary: both HTML and XHTML parsers must know the document type definition. The XHTML parser additionally must be able to read it in DTD language.

Myth: Parsing XHTML is much faster

In terms of the syntactic similarity of both languages, the speed of parsing is only determined by the skill of the programmers of the individual parsers. The time required for machine processing of a typical web page (whether HTML or XHTML) on a regular computer is imperceptible to human perception.

Myth: HTML parser must always cope

Not at all. The HTML specification does not dictate how an application should behave in case of processing an erroneous document. Due to competitive pressures in the real world, browsers have become completely tolerant of faulty HTML documents.

It is different in the case of XHTML. The specification, by referring to XML dictates that the parser must not continue processing the logical structure of the document in case of an error. Again, due to competitive pressures in the real world, RSS readers have become tolerant of faulty XML documents (RSS is an application of XML, just like XHTML).

If we were to deduce something negative about HTML from the tolerance of web browsers, then we must necessarily deduce something negative about XML from the tolerance of RSS readers. Objectively, the draconian approach of XML to errors in documents is utopian.

Conclusion?

If your mind is no longer burdened by any of the myths mentioned above, you can better perceive the difference between HTML and XHTML. Or rather, you can better perceive that there is no difference. The real difference occurs a level higher: it is the departure from SGML and the transition to the new XML.

Unfortunately, it cannot be said that XML only solves the problems of SGML and adds no new ones. I have encountered two in this article alone. One of them is the draconian processing of errors in XML, which is not in line with practice, and the other is the existence of a different DTD language inside XML, which complicates parsing and the understandability of XML documents. Moreover, the expressive capability of this language is so small that it cannot formally cover even XHTML itself, so some features must be defined separately. For a language not bound by historical shackles, this is a sad and striking finding. However, criticism of XML is a topic for a separate article.

(If I encounter more myths, I will gradually update the article. If you want to refer to them, you can take advantage of the fact that each headline has its own ID)

17 years ago v rubrice Web


The stretched buttons problem in IE

As you might know, web forms have to by styled with care, since their native look often is the best you can achieve.

That said, sometimes even default look has its bugs. A truly flagrant mistake concerns buttons in Internet Explorer (including version 7) in Windows XP. If the button's caption is too long, the browser produces such a nasty thing:

…pokračování


Texy2 – Even More Sexy!

Texy2 is a huge leap forward. More perfect, cleverer, highly customizable. And above all – even more sexy! Web application developers can chuckle in contentment.

Initially, Texy2 wasn’t even supposed to be released. But let's not get ahead of ourselves…

How Software Is Designed

The best analysis of a program is done by programming it. Only then do you realize what you really need from it. And only then can you write it perfectly.

I was aware of this while writing Texy 1. I didn’t want to write API documentation, I didn’t translate the website into other languages. I knew that was just a rehearsal for the real Texy.

The first version was a labor because I had to crack a ton of nuts. Figure out how to even do it. It’s not a joke. For instance, you might say: “Texy will insert non-breaking spaces between a preposition and a word.” And one might think a regular expression that finds v lese and replaces it with v&nbsp;lese would suffice.

But, can it handle this too: v <strong>lese</strong>? Yes, a non-breaking space belongs there too. Why wouldn’t it? Should we filter strings in angle brackets? Okay, but what about this input:

v <span title="3 > 2">lese</span>

You'd suggest more cunning HTML tag filtering? Wait, but if there’s a <br> tag, then the non-breaking space shouldn’t be there. So no filtering, but analysis instead.

Or… or just consider this! 🙂

&#x76; <span title="les > obora"> &#x0020;
<!-- hehe --></span> &#32; &#x6C;ese

It’s still about the letter v followed by a space and the word lese. Now, just try to design that regular expression in rough outline ;)

Texy2 of course can do it. And that's just one of thousands of features.

However, the precision of conversion is not the main attraction of Texy2. Nope, that’s just a manifestation of maturing older ideas. The real bombshell is the maximum customizability.

Texy is Flexible and Billable

Now you can easily change the behavior of any document element. Need to build a wiki over Texy2? I.e., control all the links on the page? It took me just a few lines of code.

Need to generate content based on headings? Want to insert flash animations using [* movie.swf *]? Want to automatically add a CSS class to all phrases "hello .(description)"? You can! And extremely easily.

Some solutions are found directly in the distribution, but mostly in the documentation, which is not yet available 🙂 At least there’s a brief changelog. I’m sorry, I have such important tasks now that there’s no time to write the manual. However, the Texy website is now designed so that creating documentation does not have to depend only on me.

Texy2 is Here

Texy2 wasn’t meant to be released. I realized that I had no motivation to release my software as open source. It comes with many limitations, in the comfort zone you won’t find (i.e., in the Czech Republic), everyone bothers with support, you encounter idiots. If it weren’t for the Giraffe & co. at the last HBWBH, I would’ve probably kept it to myself.

The revision released today with the beautiful number 111 is the first official beta version of Texy2. Download it, play around, test it.

18 years ago v rubrice PHP



PHP: The Dark Magic of Optimization

I recently managed to speed up a PHP script to a hundredth of its original execution time by changing just a few characters in the source code. How is this possible? The drastic acceleration is due to the appropriate use of references and assignments. I'll let you in on how it works. Don't believe the sensational headline; it's not any kind of black magic. I repeat, you just need to understand how PHP works internally. But don’t worry, it's nothing too complicated.

In-depth Reference Counting

The PHP core stores variable names separately from their values in memory. An anonymous value is described by the structure [zval. Besides raw data, it includes information about the type (boolean, string, etc.) and two additional items: refcount and is_ref. Yes, refcount is exactly the counter for the aforementioned reference counting.

$abc = 'La Trine';

What does this code actually do? It creates a new zval value in memory, whose data section holds the 8 characters La Trine and indicates the type as a string. At the same time, a new entry abc is added to the variable table, referring to this zval.

Additionally, in the zval structure, we initialize the refcount counter to one, because there is exactly one variable ($abc) pointing to it.

…pokračování

18 years ago v rubrice PHP


HTTP Redirection

For some, this is obvious, for me, it's mainly a cheat sheet. I just can't remember extremely long numbers, meaning those that have more than one digit.

In PHP, redirection is implemented with the following code:

$code = 301; // code in the range 300..307
$url = 'http://example.com';
header('Location: ' . $url, true, $code);
die('Please <a href="' . htmlSpecialChars($url) . '">click here</a> to continue.');

Note that after calling the header() command, it is necessary to explicitly terminate the script. It doesn't hurt to offer a text message and a link for agents that do not automatically redirect.

Types of Redirection

The meanings of individual codes are described in detail in the standard RFC 2616: HTTP/1.1 Redirection. Here they are:

300 Multiple Choices

There are several URLs to which redirection is possible (pages may differ, for example, in language). Offer users a list of these. The preferred destination can be indicated in the Location header; not every browser automatically redirects. Rarely used.

301 Moved Permanently

Use this when a resource that used to exist at the requested URL is now (permanently) located at a new address. Specify this in the Location header. However, if it has been discontinued, announce this with the code 410 Gone.

302 Found

A problematic code. It indicates that the resource has been temporarily moved elsewhere and the browser should access the new URL using the same method (GET, POST, HEAD, …) as used on the original. Additionally, with methods other than GET and HEAD, user confirmation should be required for the redirection. Most browsers, however, do not respect this and change the method to GET without requiring confirmation.

The code is often mistakenly used instead of 303.

303 See Other – for PRG

The Post/Redirect/Get technique prevents double submission of forms upon page reload or back button click. After submitting a form using the POST method, a redirection is made using the GET method to another page. This is exactly what the 303 code is for, converting POST to GET.

304 Not Modified

For caching purposes. It responds to the If-Modified-Since header that the resource has not changed since the previous visit. The response must not contain a body, only headers.

307 Temporary Redirect

As mentioned, code 302 has become problematic due to non-compliance with the standard by both web designers and browser creators. Code 307 is its reincarnation, which mostly works correctly. It can be used, for example, to perform a redirection using the POST method with transferred data.

18 years ago v rubrice PHP


The magic with conditional comments

This articles is actually an answer to e-mail by Honza Bien, who was asking me about the manipulations I was doing with conditional coments. Say, generally accepted idea is, that one kind of a comments (downlevel-hidden) is valid and the other (downlevel-revealed) is not. I tried to adapt those invalid comments the way that they would be valid. I'll explain the whole sequence.

…pokračování

19 years ago v rubrice Web



phpFashion © 2004, 2024 David Grudl | o blogu

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.