Skip to content

WordPress REJECTED MY PLUGIN!

The Rejection by Andreas WintererDear Reader,

One of the biggest complaints I hear about WordPress is that yes, you can choose from thousands of plugins, but many of them are crap. Because there was no barrier to entry, many of them were poorly coded and could even introduce security vulnerabilities to your site. I recently found out the hard way that WordPress is moving to change that. :)

First, they have been retiring old and unmaintained plugins for a while now. Thankfully, that includes all the plugins I wrote back in the 1.5-1.9 days. :) More importantly though, there is now a code review before accepting new plugins. This is a very good move on their part and I applaud them for this move.

There is a small problem though. They don’t seem to have published anything on what is acceptable/unacceptable in a plugin. In discussing my particular plugin with the reviewer, it seems the rules are kind of fuzzy as to what gets accepted or not, and they seem to be changing.

Overall, I think that a code review process is a very positive move for the WordPress ecosystem. It would be nice however, if the review team published the current rules. Even if those rules change, a current set of rules would help make sure that plugin developers don’t waste time and effort on plugins that won’t be accepted.

If these guidelines are already available, linking to them from “Writing a Plugin” would be apprecaited.

Well done, WordPress!

Until next time,
I <3 |< =C= p.s. I am working on updating my plugin to change the reported problem so that hopefully it will be accepted next time. (fingers crossed) :) Photo Credit: The Rejection by Andreas Winterer. Used under Creative Commons License.

What PHP framework should I learn?

Dear Reader,

I get asked this question every now and then. It recently came up on twitter. To me, this is like a carpenter being asked “Which hammer should I use to build a house?”.

Each of the modern PHP frameworks have their strengths and weaknesses. If you are a professional programmer, you need to be aware of the top frameworks. (No, I won’t define them here, you figure out which ones are important to your particular career) You also need to be able to work in a couple of them. “Knowing of” and “Knowing how to use” are two totally different things.

There is no “right” framework, there is the right one for the job at hand. If you only know how to work with one of them, well, then you can build your house with that particular hammer.

Professional programmers should have a variety of tools in their tool belt. No, you don’t need to know how to work in all the PHP frameworks, but you will need to know 2 or 3 of them. Invest some time in yourself and your skills. Take one weekend a month and build a small project in a framework you know OF but don’t know how to use. See if it is a better tool than the one you are currently using. The worst thing that can happen is that you learn something new.

Until next time,
I <3 |<
=C=

The PHP CachingIterator

Dear Reader,

(Sample code for those too dang lazy to cut ‘n paste)

How I got here

In the course of writing my next book, “Iterating PHP Iterators”, I found something very interesting.

I have a short chapter on the CachingIterator. One of the flags in the CachingIterator is FULL_CACHE. It was during my experiments with tha, that I found…an anomaly.

Note: As of yet, I have not reported this as a bug in PHP because it may just be a situation of “I’m doing it wrong”. I’m putting this out here mainly so someone can point me in the right direction. If no one can, then I’ll file a bug.

The proof of error code

The example I am using in my book is the 7 Dwarfs. Here is the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$dwarves = [1=>'Grumpy',
            2=>'Happy',
            3=>'Sleepy', 
            4=>'Bashful', 
            5=>'Sneezy', 
            6=>'Dopey', 
            7=>'Doc'];
$it      = new CachingIterator(new ArrayIterator($dwarves), 
                               CachingIterator::FULL_CACHE);
foreach($it as $v);
 
$it->offsetUnset(4);
$it->offsetSet('Cal','Kathy');
$it[5]='Surly'; 
 
foreach($it as $offset=>$value) {
	echo 'Original: '.$offset.' == '.$value."\n";
}

That code actually works, even if it doesn’t work the way I would expect it to. I would expect that iterating over $it would give me the modified version, not the original “cached” version. Note that Bashful is still in the list and Kathy is not. It is the original list as we loaded it into the ArrayIterator. Also, line 11 is very important, if a bit silly. Yes, you have to spin through the entire array if you pass it in on the constructor, otherwise, the cache doesn’t get loaded.

Now let’s add a little more to it.

1
2
3
foreach($it-&gt;getCache() as $offset=&gt;$value) {
	echo 'Cache: '.$offset.' == '.$value."\n";
}

This now outputs:

$ php ../examples/test.php 
Original: 1 == Grumpy
Original: 2 == Happy
Original: 3 == Sleepy
Original: 4 == Bashful
Original: 5 == Sneezy
Original: 6 == Dopey
Original: 7 == Doc
Cache: 1 == Grumpy
Cache: 2 == Happy
Cache: 3 == Sleepy
Cache: 4 == Bashful
Cache: 5 == Sneezy
Cache: 6 == Dopey
Cache: 7 == Doc

Ok, so now, even when we pull the cache, we still get the original list. I’m not sure how that is right, ever. I know a few of you are saying “but Cal, you have to rewind().” It is to those of you who I say “read my book”. :) But just for grins and giggles, let’s rewind the iterator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
 
$it = null;
 
$dwarves = [1=>'Grumpy',
            2=>'Happy',
            3=>'Sleepy', 
            4=>'Bashful', 
            5=>'Sneezy', 
            6=>'Dopey', 
            7=>'Doc'];
 
$it      = new CachingIterator(new ArrayIterator($dwarves), 
                               CachingIterator::FULL_CACHE);
foreach($it as $v);
 
$it->offsetUnset(4);
$it->offsetSet('Cal','Kathy');
$it[5]='Surly'; 
 
foreach($it as $offset=>$value) {
	echo 'Original: '.$offset.' == '.$value."\n";
}
 
$it->rewind();
 
foreach($it->getCache() as $offset=>$value) {
	echo 'Cache: '.$offset.' == '.$value."\n";
}
</code>

Now when we run it we get this:

$ php ../examples/test.php 
Original: 1 == Grumpy
Original: 2 == Happy
Original: 3 == Sleepy
Original: 4 == Bashful
Original: 5 == Sneezy
Original: 6 == Dopey
Original: 7 == Doc
Cache: 1 == Grumpy

Hmmm…well that ain’t right.

Here is what DID work. I am not entirely sure why at this point, I’m still investigating.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$dwarves = [1=>'Grumpy',
            2=>'Happy',
            3=>'Sleepy', 
            4=>'Bashful', 
            5=>'Sneezy', 
            6=>'Dopey', 
            7=>'Doc'];
 
$it      = new CachingIterator(new ArrayIterator($dwarves), 
                                   CachingIterator::FULL_CACHE);
foreach($it as $v);
 
$it->offsetUnset(4);
$it->offsetSet('Cal','Kathy');
$it[5]='Surly'; 
 
foreach($it->getCache() as $offset=>$value) {
	echo 'Cache: '.$offset.' == '.$value."\n";
}
 
foreach($it as $offset=>$value) {
	echo 'Original: '.$offset.' == '.$value."\n";
}

Now we are through the looking glass. The order in which the loops appear in your code makes a difference? Technically, this code outputs the list correctly if you ignore the fact that the cache version should be the immutable one and that $it itself should reflect the changes.

$ php ../examples/test.php 
Cache: 1 == Grumpy
Cache: 2 == Happy
Cache: 3 == Sleepy
Cache: 5 == Surly
Cache: 6 == Dopey
Cache: 7 == Doc
Cache: Cal == Kathy
Original: 1 == Grumpy
Original: 2 == Happy
Original: 3 == Sleepy
Original: 4 == Bashful
Original: 5 == Sneezy
Original: 6 == Dopey
Original: 7 == Doc

BONUS ROUND:

Take the above code, now swap the two foreach statements. See what I mean? The order that the foreach statements are executed in should have absolutely no effect on the output. If this is expected behavior then we kinda need to put it in the manual.

Sooooo…TIL. don’t use the FULL_CACHE flag on the CachingIterator. I am not sure what the FULL_CACHE flag is supposed to do, but it doesn’t seem to do anything useful at the moment.

Summary:

So today I learned, don’t use the FULL_CACHE flag on the CachingIterator. I am not sure what the FULL_CACHE flag is supposed to do, but it doesn’t seem to do anything useful at the moment. Also, it can screw things up for you.

Here are 3 takeaways.

  1. The ‘cached’ version of the iterator should be the one that does NOT change. The iterator itself should reflect the changes made.
  2. Calling rewind() should never cause the cache to forget everything except the last element.
  3. If you pass in the ArrayIterator in the constructor, it does not get loaded into the cache, you have to put an empty foreach loop in your code to load the cache.

I hope this helps someone along the way.

Until next time,
I <3 |<
=C=

Signaling PHP

Dear Reader,

PrintI’ve just finished my 3rd book – and my first mini-book – and wanted to tell you about it.

“Signaling PHP” is about using PCNTL signals like SIGINT in PHP command line scripts.

Most of the PHP I write these days is CLI scripts. I really wanted to be able to trap signals in some of my scripts. I struggled with this for a while; I even spent an entire weekend googling and reading only to find out that most of the information out there was either wrong, confusing, or incomplete. I decided that once I figured it out, I was going to put everything I learned together in one place to help others that were struggling with this topic as well.

So it is that I present to you “Signaling PHP”. The book is approximately 30 pages long, and is available in PDF, Kindle, and mobi formats.

You can get your copy by visiting http://signalingphp.com.

Until next time,
I <3 |<
=C=

Using 3rd party libraries in Composer projects

Dear Reader,

Recently, I discussed a lesson I learned about “Managing the Verbosity of symfony’s Command Object With a Trait” while building a project. This particular project has been very instructional to me so I thought I would share something else I learned.

As discussed in the previous post, this is a command line script to move email addresses from eventbrite events into MailChimp lists. I wrote it specifically for use with my NomadPHP project but the way it now works, it operates on all my projects at once.

A problem I ran into when starting this project is that the official MailChimp API wrapper for PHP is NOT a Composer package. Thankfully, the wizards behind Composer have thought this through. To facilitate using non-Composer packages in composer projects, all I had to do is add one line to my “autoload” section of my project:

    "autoload": {
        "psr-0": {
	   "NomadPHP": "app/"},
 	   "classmap": [ "src/"]				  
	}

The classmap section allows me to drop any class file into the directory src/ and then run composer.phar update. Composer will look at the files in that directory and add them to vendor/composer/autoload_classmap.php. Mine now looks like this:

<?php

// autoload_classmap.php generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Eventbrite' => $baseDir . '/src/Eventbrite.php',
    'MCAPI' => $baseDir . '/src/MCAPI.class.php',
);

Problem solved. As you can see I also used this to be able to use the eventbrite API wrapper as well.

If you are not using Composer for your projects, you really need to start. It’s a great way to speed your PHP development.

Until next time,
I <3 |<

=C=