Download Firefox -  a safer, easier to use web browser. Return to iribbit.net - Leap into the online experience! Return to iribbit.net - Leap into the online experience! iribbit.net - Leap into the online experience!

Project News :.

The latest project to launch was the site for Gorilla Offroad Company. Aside from their main site, a social media strategy was develop to launch the company into various industry specific automobile enthusist discussion board communities as well as popular social media fronts like Facebook, Pinterest, and Twitter.


Valid XHTML 1.0 Transitional

Valid CSS!

Section 508 Compliant

powered by: Macromedia ColdFusion MX

made with: Macromedia Dreamweaver MX

What is RSS

XML - often denotes RSS Feed information.

Macromedia - ColdFusion Programming
white horizontal rule

ColdFusion News :.

To bring a little life to my site, I've pulled a couple What is RSS Feeds into this page. You can currently choose between the technology related news stories from the following news sources:



You are currently viewing and RSS Feed from coldfusionbloggers.org.



Woocommerce testing if a product is in a descendent category
To test whether a WordPress post is within a particular category or any of its subcategories, there’s a handy snippet in the WordPress codex here: http://codex.wordpress.org/Function_Reference/in_category#Testing_if_a_post_is_in_a_descendant_category For WordPress noobs like me (and what environment has more noobs than WordPress?), though, it’s not obvious how to make that work for Woocommerce product categories. There are two […]
(Thu, 02 Oct 2014 00:00:23 GMT)
[view article in new window]

Vote for Railo on Bitnami
Please vote to get Railo added to Bitnami.
(Thu, 02 Oct 2014 00:00:12 GMT)
[view article in new window]

Nano-optimsation of looping code. Fascinating but pointless
G'day:
It's PHP, Railo and ColdFusion today. A few days ago I was researching my "PHP: looking at some interesting "unexpected" behaviour with references" article which related to a StackOverflow question: "Assign by reference bug". One statement in one of the answers fascinated me:
(using reverse looping mostly because not enough people remember that's a thing you can do, and is more efficient than a forward loop =)
Interesting. And sounded like something I could get my teeth into and have a look at.

I didn't immediately get why this would be the case, but did some Googling and found a bunch of interesting articles / Stack Overflow questions/answers, and the reasoning made sense.

Consider a generic for loop:

for(initialisationStatement; conditionalExpression; iterationExpression)

EG:

for (i=1; i <= 10; i++)

  • The initialisationStatement is executed once at the beginning of the code block.
  • The conditionalExpression is evaluated at the beginning of every iteration. When it's false, processing skips to after the end of the block.
  • The iterationExpression is executed at the end of each iteration.
  • All three are optional.
  • The conditionalExpression needs to evaluate to a boolean value.

Let's consider one of these loops, over an array:

for ($i=0; $i < count($array); $i++)


  • $i=0 is run once
  • count($array) is run ten times
  • and its result is compared to $i ten times
  • $i is incremented ten times

Loosely speaking there's 31 operations there (some are weightier than others, I know).

Now consider this:

for ($size=count($array)-1; $size-- >= 0;)
  • $size is initialised once
  • count($array) is called once
  • $size-- is compared to a static value ten times

12 operations. With the weightiest one - count() - now being run once instead of ten times.

Oh, and yeah, the boolean check and the decrement could be considered two operations, but you get my point: there's still fewer operations. Also remember that as a boolean expression, it's lighter weight than the previous example as it's not comparing two variables.

This can be "improved" even further. Consider what happens when we do i--:
  • The current value of i is stored
  • i is decremented
  • The previously stored value is returned
If we used --i instead, it's this:
  • i is decremented
  • and returned

More relevant-ish reading on quirks of these sort of operators: No, the ++ operators are not thread safe.

If you have any sense, you'll be rolling your eyes about all this as the sort of optimisations we're talking about here are shrinkingly inconsequential, and require somewhat unorthodox code. So is it worth it?

Let's see. Here's some tests in CFML:

// baseline.cfm

URL.size = URL.size ?: 1

function getSize(size){
return size
}


timeJob = function(message, job) {
var start = getTickCount()
job()
var end = getTickCount()
var duration = end - start
echo("#message#: #duration#ms<br>")
}


echo("<h3>Running #size# iterations</h3>");

timeJob("Baseline (ascending)", function(){
for (var i=1; i <= getSize(URL.size); i++){
var b = i
}
})

timeJob("Using variable for length (ascending)", function(){
var iterations = getSize(URL.size)
for (var i=1; i <= iterations; i++){
var b = i
}
})

timeJob("Post decrement (descending)", function(){
for (var i=getSize(URL.size)+1; i--;){ // (n-1)-0
var b = i
}
})

timeJob("Pre decrement (descending)", function(){
for (var i=getSize(URL.size)+1; --i;){
var b = i
}
})

timeJob("Pre decrement with additional operation (descending)", function(){
for (var i=getSize(URL.size)+1; --i;){
var b = i
var c = i
}
})

Notes:
  • There's a ColdFusion 11 version of this file here: baselineColdFusion.cfm.
  • I'm not using an array here, but a faux function call which gets the number of iterations to run. The reason being that the number of iterations I need to do to amplify the results until they were distinct was killing my PHP install (out of memory). Pleasingly, Railo coped OK, but I wanted a like-for-like test, so just ran with code which would work on both platforms
  • I have a function which times a job.
  • And a bunch of calls to it. All the jobs simply loop the number of times requested, doing a small amount of work.
  • Note that one of the loops iterates (n-1) to 0 instead of n to 1; the important thing in these loops is the number of iterations, not the index value.
  • Each job in turn refines the looping strategy, inline with my discussion above.
  • The last job has twice as much work to do within each iteration.
Here's the equivalent PHP code:

// baseline.php

$size = isset($_GET["size"]) ? $_GET["size"] : 1;

function getSize($size){
return $size;
}


$timeJob = function($message, $job) {
$start = microtime(true);
$job();
$end = microtime(true);
$duration = (int)(($end - $start) * 1000);
echo sprintf("%s: %sms<br>", $message, $duration);
};


echo "<h3>Running $size iterations</h3>";

$timeJob("Baseline (ascending)", function() use ($size){
for ($i=1; $i <= getSize($size); $i++){
$b = $i;
}
});

$timeJob("Using variable for length (ascending)", function() use ($size){
$iterations = getSize($size);
for ($i=1; $i <= $iterations; $i++){
$b = $i;
}
});

$timeJob("Post decrement (descending)", function() use ($size){
for ($i=getSize($size); $i--;){ // (n-1)-0
$b = $i;
}
});

$timeJob("Pre decrement (descending)", function() use ($size){
for ($i=getSize($size)+1; --$i;){
$b = $i;
}
});

$timeJob("Pre decrement with additional operation (descending)", function() use ($size){
for ($i=getSize($size)+1; --$i;){
$b = $i;
$c = $i;
}
});

OK, so how does this lot fare? I had to run 100000 iterations to get results I could see, so the TL;DR of all this is "it's simply not worth worrying about". But there is a real difference. Check this out:

Railo:

Running 100000 iterations

Baseline (ascending): 120ms
Using variable for length (ascending): 51ms
Post decrement (descending): 57ms
Pre decrement (descending): 51ms
Pre decrement with additional operation (descending): 46ms


ColdFusion:

Running 100000 iterations

Baseline (ascending): 207ms
Using variable for length (ascending): 9ms
Post decrement (descending): 3ms
Pre decrement (descending): 3ms
Pre decrement with additional operation (descending): 3ms


PHP:

Running 100000 iterations

Baseline (ascending): 72ms
Using variable for length (ascending): 29ms
Post decrement (descending): 7ms
Pre decrement (descending): 7ms
Pre decrement with additional operation (descending): 8ms


All these results are a fair "standard" result, when checking about 20-30 runs for each platform.

Interestingly... ColdFusion is fastest. Also interestingly: Railo is overall a lot slower (comparatively). Well: Railo seems better at calling functions (the top result): but for basic looping operations, it's quite a bit slower.

But... come on... a few (or few tens) of milliseconds over 100000 iterations? Who the hell cares?

I included the last test in there - the one with the doubling-up of the operations - as I wondered whether any looping improvement would be lost in the noise of what the looped code was actually doing. In this example it was not really the case. Everything just ran fast. Obviously though, if the loop had heavier duty operations in it like DB hits or a bunch of function calls... a better place to make gains would be too optimise that code. It's simply not worth optimising the looping construct.

What I would attempt to do is to make the looping code clear in its intent. I'd generally never use one of these general purpose loops to - for example - loop over an array. If I was wanting to do something with each element, I'd call Array.each() (perhaps array_walk() in PHP); if I was wanting to update each element of an array, I'd call a map() function; if I wanted to derive a value from an array, I'd call reduce(). etc. Write code that best describes what you're doing. Don't piss about writing non-descriptive code because you think it might be a bit faster. Because - almost always - that would not matter. And I'd not even use a generic solution (for(value in array) in CFML or foreach($array as $key=>$value) in PHP); I'd use the functionality that best describes the operation.

Interesting stuff, but also a lesson in "what not to bother with", I reckon. It's kinda nice to be aware of the differences of the "inner" workings of things though, eh?

Righto.

--
Adam
(Wed, 01 Oct 2014 18:10:48 GMT)
[view article in new window]

Hypermedia API Client Success
Mike Admundsen visited the Lonely Planet offices recently and spent all day discussing the current state of API development, and thoughts on what the future holds – for those brave enough to take the risk. One thing that I walked away from the day-long event with was the thought, “Ok, so we’ve mostly been doing […]
(Wed, 01 Oct 2014 18:00:17 GMT)
[view article in new window]

Thanks for making ColdBox Developers Week 2014 a success!

As we're recovering from our third annual ColdBox Developers Week, we'd like to give a shout out of thanks to everyone who participated. From our sponsors, to the speakers and the attendees; everyone helped play a part in making these 21 training sessions fun and informative. We hope everyone had as much fun learning as we did putting this on.

Prizes

Thanks to our sponsors, Ortus Solutions and Computer Know How, we had tons of prizes to give away. Here's a recap of the winners. Congratulations!

Furthermore, we offered additional prizes to the first two people to submit new packages to ForgeBox-- CFML's newest and most comprehensive code repository. The following two people stepped up:

Recordings

The most common question I've gotten is, "Was this session recorded?" The answer is, YES! Every session including our special guest session by Gert Franz of Railo was recorded and is posted along with the slide decks over on the CBDW 2014 recording page.

http://www.coldbox.org/media/cbdw2014

Resources

Hopefully you came away from CBDW excited to try out some of the tooling you learned about. We're here to help you with that. Here's some links for you to get started:

Donate

Ortus Solutions spends a lot of time putting on free training for the CFML community. If your company benefited from this free event, please consider donating back so we can do even more free stuff for the CF community.

Secure Donation via PayPal


(Wed, 01 Oct 2014 18:00:08 GMT)
[view article in new window]

Cordova, Plugins, and Determining What Supports What

Earlier today a user on the Cordova development list asked if plugins are tested against only the current release of the SDK. This brought up an interesting discussion that I'm summarizing here.

First, there is still an idea of "core" plugins versus "third party" plugins. Core plugins include the things that have traditionally been part of the core feature set, like Camera and Geolocation. While there is no firm list of what is considered core, I'd say anything under the org.apache.cordova namespace is core. You can see a list of them here: http://plugins.cordova.io/#/search?search=org.apache.cordova

The question was - in general - when a new version of a plugin is released, is it tested against the most recent version of Cordova.

The answer is yes. Nice and simple. Michal Mocny (Apache Cordova committer) had this to say:

"When we do a platform release, we test with the latest plugins to make sure the platform isn't breaking things. When we do a plugins release, we test with the latest platforms to make sure the plugins are not breaking things."

Again, nice and simple. Michal also mentioned something I hadn't noticed before. If you go to plugins.cordova.io and view an individual plugin, you may see this:

This comes from the plugin's plugin.xml file containing the engine tag. As an example:


<engines>
<engine name="cordova" version=">=3.0.0" />
</engines>

Unfortunately, not all plugins use this, and obviously you have to trust the developer when they said they've tested something.

It is also worth nothing that the engine referenced above refers to the CLI, not an individual platform release. It should still be relatively safe, but keep that in mind as well.


(Wed, 01 Oct 2014 12:00:25 GMT)
[view article in new window]

Looking at PHP's OOP from a CFMLer's perspective: object serialisation
G'day:
This continues my series which is thusfar:


The next section in the PHP OO docs is actually "Magic Methods" (oh please), but two of these are __sleep() and __wakeup(), and these relate to object serialisation, so I decided to have a look at how this works, and __sleep() and __wakeup() at the same time.



Firstly, here's a quick CFML example (this will run only on Railo, not ColdFusion, as it leverages stuff only Railo have thusfar implemented):

// Movie.cfc

component {

public Movie function init(required title, required year, required Person director) {
variables.title = title
variables.year = year
variables.director= director

return this
}

public function get() {
return [
title = title,
year = year,
director= director.getFullName()
]
}

public function getDirector(){
return director
}

}

// Person.cfc
component {

public Person function init(required firstName, required lastName){
variables.firstName= firstName
variables.lastName = lastName
return this
}

public function getFullName() {
return "#variables.firstName# #variables.lastName#"
}

}

<cfscript>
// movie.cfm

movie = new Movie("Once Were Warriors", 1994, new Person("Lee", "Tamahori"))

serialisedMovie = serialize(movie)
dump(serialisedMovie)
echo("<hr>")

deserialisedMovie = evaluate(serialisedMovie)

dump(var=deserialisedMovie.get(), label=getMetadata(deserialisedMovie).fullName)

director = deserialisedMovie.getDirector()
dump(var=director.getFullName(), label=getMetadata(director).fullName)
</cfscript>


Here we have a simple Movie class which has title, year and director, with the director being an instance of another class Person. I use Railo's serialize() function to serialise the movie, have a look at what it outputs, and then deserialise it again using - of all things - evaluate(). I then dump out the results of the deserialisation to check it's actually worked properly.

Here's the output:

stringevaluateComponent('scribble.shared.scratch.php.www.experiment.oo.serialisation.Movie','62aa1eb53f27541110d76b787d585ef6',{},{'DIRECTOR':evaluateComponent('scribble.shared.scratch.php.www.experiment.oo.serialisation.Person','b459ac28aa7dd48158ddfb3466213bfe',{},{'LASTNAME':'Tamahori','FIRSTNAME':'Lee'}),'YEAR':1994,'TITLE':'Once Were Warriors'})

scribble.shared.scratch.php.www.experiment.oo.serialisation.Movie
Array
1
stringOnce Were Warriors
2
number1994
3
stringLee Tamahori
scribble.shared.scratch.php.www.experiment.oo.serialisation.Person
stringLee Tamahori

Excellent.

OK, now for PHP. Here's code roughly analogous to the CFML code above:

<?php
// Movie.class.php

class Movie
{
use Message;

private $title;
private $year;
private $director;

public function __construct($title, $year, $director)
{
$this->title = $title;
$this->year = $year;
$this->director = $director;
}

public function get()
{
return [
"title" => $this->title,
"year" => $this->year,
"director" => $this->director->getFullName()
];
}

}


<?php
// Person.class.php

class Person
{
private $firstName;
private $lastName;

public function __construct($firstName, $lastName)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
}

public function getFullName()
{
return "$this->firstName $this->lastName";
}

}


<?php
// movie.php

require_once "./app.php";

$movie = new Movie("Once Were Warriors", 1994, new Person("Lee", "Tamahori"));

$serialisedMovie = serialize($movie);


echo "<pre>$serialisedMovie</pre><hr>";

$deserialisedMovie = unserialize($serialisedMovie);

new dBug([get_class($deserialisedMovie), $deserialisedMovie->get()]);

And the result is equivalent too:

O:5:"Movie":3:{s:12:"Movietitle";s:18:"Once Were Warriors";s:11:"Movieyear";i:1994;s:15:"Moviedirector";O:6:"Person":2:{s:17:"PersonfirstName";s:3:"Lee";s:16:"PersonlastName";s:8:"Tamahori";}}

[get_class($deserialisedMovie), $deserialisedMovie->get()] (array)
0Movie
1
array
titleOnce Were Warriors
year1994
directorLee Tamahori

Nice one.

__sleep() / __wakeup()

What about these __sleep() and __wakeup() methods? They don't actually play much of a part in the serialisation - which clearly works fine without them - but are just basically event handlers. If you need to do anything before serialising, or before deserialising. The docs use examples of, say, committing data before serialising, or reestablishing DB connections etc before deserialising.

Here I've updated Movie and Person to have stub methods which simply report they were called:

<?php
// Movie.class.php

class Movie
{
// ... snipped for clarity ...

public function __sleep()
{
SELF::message(__CLASS__, __FUNCTION__, func_get_args());
return ["title", "year", "director"];
}

public function __wakeup()
{
SELF::message(__CLASS__, __FUNCTION__, func_get_args());
}

}

<?php
// Person.class.php

class Person
{
// ... snipped for clarity ...

public function __sleep()
{
SELF::message(__CLASS__, __FUNCTION__, func_get_args());
return ["firstName", "lastName"];
}

public function __wakeup()
{
SELF::message(__CLASS__, __FUNCTION__, func_get_args());
}

}

Output:

Movie->__sleep() called with arguments:
[]


Person->__sleep() called with arguments:
[]


O:5:"Movie":3:{s:12:"Movietitle";s:18:"Once Were Warriors";s:11:"Movieyear";i:1994;s:15:"Moviedirector";O:6:"Person":2:{s:17:"PersonfirstName";s:3:"Lee";s:16:"PersonlastName";s:8:"Tamahori";}}

Person->__wakeup() called with arguments:
[]


Movie->__wakeup() called with arguments:
[]


[get_class($deserialisedMovie), $deserialisedMovie->get()] (array)
0Movie
1
array
titleOnce Were Warriors
year1994
directorLee Tamahori

You can see that the __sleep() handler from both Movie and Person were called during the serialisation process, and __wakeup() for both called during deserialisation.

Cool.

Note how I'm returning a list of properties from __sleep():

return ["title", "year", "director"];

That's the list of properties that will be included in the serialisation. I'm just gonna change that to:

return ["title", "year"];

And run this test instead:

<?php
// movieWithoutDirector.php

require_once "./app.php";

$movie = new Movie("Once Were Warriors", 1994, new Person("Lee", "Tamahori"));

$serialisedMovie = serialize($movie);
echo "<pre>$serialisedMovie</pre><hr>";

$deserialisedMovie = unserialize($serialisedMovie);
echo "<pre>";
var_dump($deserialisedMovie);
echo "</pre>";

And the output:

Movie->__sleep() called with arguments:
[]


O:5:"Movie":2:{s:12:"Movietitle";s:18:"Once Were Warriors";s:11:"Movieyear";i:1994;}

Movie->__wakeup() called with arguments:
[]


object(Movie)#4 (3) {
["title":"Movie":private]=>
string(18) "Once Were Warriors"
["year":"Movie":private]=>
int(1994)
["director":"Movie":private]=>
NULL
}

Here the director property has been completely ignored from the serialisation process, and accordingly when it was deserialised the director is null.

Serializable

There is another approach one can take with this. PHP has a Serializable interface, which requires two methods being implemented: serialize() and unserialize(). In this case, when an object is (de)serialised, these methods are called instead.

Here's an updated version of the Movie and Person classes:

<?php
// Movie.class.php

class Movie implements Serializable
{
// ... snipped for clarity ...

public function serialize()
{
SELF::message(__CLASS__, __FUNCTION__, func_get_args());
$arrayToSerialise = $this->get();
return json_encode($arrayToSerialise);
}

public function unserialize($serialized)
{
SELF::message(__CLASS__, __FUNCTION__, func_get_args());
$deserialisedArray = json_decode($serialized);

$this->title = $deserialisedArray->title;
$this->year = $deserialisedArray->year;

$director = Person::unpackFullName($deserialisedArray->director);
$this->director = new Person($director["firstName"], $director["lastName"]);
}

// ... snipped for clarity ...

}


<?php
// Person.class.php

class Person
{
// ... snipped for clarity ...

public static function unpackFullName($fullName)
{
$asArray = explode(" ", $fullName);
return [
"firstName" => $asArray[0],
"lastName" => $asArray[1]
];
}

}

There's nothing particularly gripping here (and note the added method to Person is just to assist unserialize() from Movie), I simply use JSON as the serialisation method. Here's the output:

Movie->serialize() called with arguments:
[]


C:5:"Movie":68:{{"title":"Once Were Warriors","year":1994,"director":"Lee Tamahori"}}

Movie->unserialize() called with arguments:
["{\"title\":\"Once Were Warriors\",\"year\":1994,\"director\":\"Lee Tamahori\"}"]


[get_class($deserialisedMovie), $deserialisedMovie->get()] (array)
0Movie
1
array
titleOnce Were Warriors
year1994
directorLee Tamahori


Note that __sleep() and __wakeup() are not called when using Serialisable (this is documented, and by design).

That's about it, as far as my findings go with PHP's object serialisation. Other than some dodgy function names, the implementation seems fine to me.

--
Adam
(Tue, 30 Sep 2014 17:52:54 GMT)
[view article in new window]

PHP: another generator example: primes
G'day:
Duncan has mused me again. He's reworking his Project Euler exercises that he'd previously done in CFML, and is now implementing in PHP. In yesterday's exercise he was looking at prime numbers: "Project Euler: problem 7 (PHP)". I thought there was scope for another exercise in using PHP generators in this for me (see previous: "PHP: generators").

So I've come up with this implementation:

<?php
// primes.php

function createPrimeSequence($length=-1)
{
$primes = [];
$potential = 1;
while ($length==-1 || sizeof($primes) < $length) {
$potential++;
$upperThreshold = sqrt($potential);
foreach($primes as $prime){
if ($prime > $upperThreshold){
break;
}
if ($potential % $prime == 0){
continue 2;
}
}
$primes[] = $potential;
yield end($primes);
}
}

$primesSequence = createPrimeSequence();

for ($i=1; $i <= 20; $i++){
echo $primesSequence->current() . " ";
$primesSequence->next();
}

echo "<hr>";
foreach(createPrimeSequence(10) as $prime){
echo "$prime ";
}


The prime calculation logic is pedestrian so I'll ignore that, the new conceit here is that I've added a $length argument to define a... well... length to the sequence, rather than it just continuing forever, as it did in the Fibonacci example. This means I can use it directly in a foreach() loop.

Oh, this outputs:

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71

2 3 5 7 11 13 17 19 23 29


New stuff I learned whilst doing this:

  • how PHP emulates optional arguments by being able to specify a default. It seems one cannot have a truly optional argument though.
  • sqrt() is PHP's square root function.
  • Both break and continue can exit multiple levels of looping, by specifying a number of levels to exit from (default is 1). Here I use continue 2 to break out of the inner foreach() loop, but also jump out of the current iteration of the while() loop.
  • the $array[] syntax is shorthand for array_push($array)
  • end() returns the last entry in an array, differing from array_pop() as it leaves the array intact.
There's nothing earth-shattering here, but I was pleased with the result, and I've definitely warmed to the idea of generators.

--
Adam
(Tue, 30 Sep 2014 17:52:54 GMT)
[view article in new window]

PHP: significant oversight in the implementation of array_reduce() (and I find the PHP bugbase...)
G'day:
I was fishing around in Stack Overflow this morning for a quick PHP exercise to do before getting out of bed (there's some imagery for you), seeking coffee, and getting on with the day.

I found this one: "Explode my Array, remove dash from key, then Implode it back together". It already had an accepted answer which involved just a coupla foreach() loops, but I thought I could come up with something more descriptive using array_reduce(). And I thought I'd post it anyway as an alternative approach.

However I ran into a problem.

First, a CFML solution to demonstrate how it should work. The problem is that some array keys (in PHP there's just arrays: I'm using a CFML struct here, but that's just an associative array in PHP), have dashes in them, and these need to be changed to spaces:

// stackoverflow.cfm

li_1 = "suffix 1"
li_2 = "suffix 2"
temp_content = "content"

pages = {
'Administrator' = {
'network-administrator' = {
'title' = 'Network ' & li_1,
'description' = 'Network ' & li_1 & ' ' & temp_content,
'post' = '<p>Network ' & li_1 & ' ' & temp_content & '.</p>'
},
'database administrator' = {
'title' = 'Database ' & li_1,
'description' = 'Database ' & li_1 & ' ' & temp_content,
'post' = '<p>Database ' & li_1 & ' ' & temp_content & '.</p>'
}
},
'Analyst' = {
'business systems analyst' = {
'title' = 'Business Systems ' & li_2,
'description' = 'Business Systems ' & li_2 & ' ' & temp_content,
'post' = '<p>Business Systems ' & li_2 & ' ' & temp_content & '.</p>'
},
'data-analyst' = {
'title' = 'Data ' & li_2,
'description' = 'Data ' & li_2 & ' ' & temp_content,
'post' = '<p>Data ' & li_2 & ' ' & temp_content & '.</p>'
}
}
}

newPages = pages.map(function(key,value){
return value.reduce(function(reduction, key, value){
key = key.replace("-", " ", "all")
reduction[key] = value
return reduction
}, {})
})

dump([pages, newPages])

So I just use a map() call to traverse each element of the outer struct, and for each of those I perform a reduction which actually returns the same array again, just with the keys "fixed".

This works fine:

Array
1
Struct
Administrator
Struct
database administratorvar.database administrator
network-administrator
Struct
Analystvar.Analyst
2
Struct
Administrator
Struct
database administratorvar.database administrator
network administrator
Struct
Analystvar.Analyst

(I've collapsed a lot of it to just demonstrate that the "network-administrator" has been fixed to "network administrator").

So I set about doing the same with PHP's array_map() and array_reduce(). But it's not possible. Because the only thing passed into array reduce is the reduction (ie: the result of the previous iteration) and the current element's value. But not its key. And there's no way to access the element's key via some other circuitous route. This would be almost understandable if a PHP array was simply an indexed array like in CFML, but it's not. The keys can be a simple numeric index, but they can also be anything else as well (they're ordered structs with default sequential numeric keys, basically). And so the key is kinda important info to pass to the iteration methods. This is, btw, not limited to array_reduce(): array_map() also doesn't expose it, and I presume the rest of them don't too.

So I googled about and found the PHP bugbase. And indeed I found a ticket covering this very shortfall: "array_reduce() callback should receive current key/index" (65872). I've voted for it, and I'll probably stick a comment on it too, to suggest following CFML's lead here.

Now here's a question for you. I'm not entirely convinced by my approach to using reduce() to actually just modify the struct, rather than really "reduce" it, per se. I know it works, but I dunno if this solution actually does fall within my intention of making the code clearer in intent than just using a coupla generic loops? What I really want is a remap() method (so like a map(), except I can specify new key names, which map() won't allow. Thoughts? Am I getting too picky? (Sean, I hope you're reading this, as I know you'll have an informed opinion on this ;-).

Righto. Coffee time.

--
Adam
(Tue, 30 Sep 2014 17:52:54 GMT)
[view article in new window]

PHP: looking at some interesting "unexpected" behaviour with references
G'day:
A week or so ago I was fascinated by this Stack Overflow question: "How to changing value in $array2 without referring $array1?". It offers this code:

// baseline.php

$array1 = array(1,20);
$x = &$array1[1];
$array2 = $array1;
$array2[1] = 22;
print_r($array1[1]); // Output is 22

And this result:

22

In PHP, as the = operator makes a copy of the variable being assigned, so one (and when I say "one", I mean "the person asking the question, and myself as well") might be surprised to see the answer is "22", rather expecting it to be "20". Surely $array1[1] is discrete from $array2[1], and $array1[1] should not be impacted by the change to $array2[1]. $x is not a macguffin in this: remove that line, and things behave "as expected". How is making $x - a reference to $array1[1] - somehow intertwined with $array2??


That initial question was followed-up by another one: "Assign by reference bug", and that has a good answer which explains theoretically what's going on. The key part is this:

This is explained over at the PHP manual (even if you have to spend more time than you should have to in order to find it), specifically over at http://php.net/manual/en/language.types.array.php#104064

The "shared" data stays shared, with the initial assignment just acting as an alias. It's not until you start manipulating the arrays with independent operations like ...[] = ... that the intepreter starts to treat them as divergent lists, and even then the shared data stays shared so you can have two arrays with a shared first n elements but divergent subsequent data.
And the relevant extract from the docs says:

please note that when arrays are copied, the "reference status" of their members is preserved (http://www.php.net/manual/en/language.references.whatdo.php).
And on that page:

In other words, the reference behavior of arrays is defined in an element-by-element basis; the reference behavior of individual elements is dissociated from the reference status of the array container.
OK, cool, I believe it. However I wanted to see it in action.

My first hurdle here was getting a lucid/helpful answer to "PHP determine if a variable is a reference". Most answers I spotted initially were "no, can't be done. Why even would you want to?" (but not in a "let's see if there's another approach" sense,  but in a "I'm getting defensive about PHP" sense).

However that's not strictly true, as it turns out. I switched my googling to "PHP reference count", and the first link got me pointed in the direction of  XDebug, which enables one to inspect reference counts and stuff like that.

Here's a reworked version of the code above, with some debug:

// baselineWithDebug.php

echo "<hr><h3><code>numbers</code> created</h3>";
$numbers = array("tahi", "rua", "toru");
xdebug_debug_zval('numbers');


echo "<hr><h3><code>refToSecondElement</code> created</h3>";
$refToSecondElement = &$numbers[1];
xdebug_debug_zval('numbers');
xdebug_debug_zval('refToSecondElement');


echo "<hr><h3><code>copyOfNumbers</code> created</h3>";
$copyOfNumbers = $numbers;
xdebug_debug_zval('numbers');
xdebug_debug_zval('refToSecondElement');
xdebug_debug_zval('copyOfNumbers');


echo "<hr><h3><code>copyOfNumbers[1]</code> changed</h3>";
$copyOfNumbers[1] = "two";
xdebug_debug_zval('numbers');
xdebug_debug_zval('refToSecondElement');
xdebug_debug_zval('copyOfNumbers');


echo "<hr><h3><code>copyOfNumbers[2]</code> changed</h3>";
$copyOfNumbers[2] = "three";
xdebug_debug_zval('numbers');
xdebug_debug_zval('refToSecondElement');
xdebug_debug_zval('copyOfNumbers');

The key elements here are:

  • there's an initial array, $numbers;
  • I make a reference to one element of it as $refToSecondElement;
  • I copy $numbers as $copyOfNumbers;
  • I change the value of the second element of $copyOfNumbers;
  • and also the third element of same.
  • Along the way I output some debug regarding each variable.
The output is fascinating:


numbers created

numbers:
(refcount=1, is_ref=0),
array (size=3)
0 => (refcount=1, is_ref=0),string 'tahi' (length=4)
1 => (refcount=1, is_ref=0),string 'rua' (length=3)
2 => (refcount=1, is_ref=0),string 'toru' (length=4)

refToSecondElement created

numbers:
(refcount=1, is_ref=0),
array (size=3)
0 => (refcount=1, is_ref=0),string 'tahi' (length=4)
1 => (refcount=2, is_ref=1),string 'rua' (length=3)
2 => (refcount=1, is_ref=0),string 'toru' (length=4)
refToSecondElement:
(refcount=2, is_ref=1),string 'rua' (length=3)

copyOfNumbers created

numbers:
(refcount=2, is_ref=0),
array (size=3)
0 => (refcount=1, is_ref=0),string 'tahi' (length=4)
1 => (refcount=2, is_ref=1),string 'rua' (length=3)
2 => (refcount=1, is_ref=0),string 'toru' (length=4)
refToSecondElement:
(refcount=2, is_ref=1),string 'rua' (length=3)
copyOfNumbers:
(refcount=2, is_ref=0),
array (size=3)
0 => (refcount=1, is_ref=0),string 'tahi' (length=4)
1 => (refcount=2, is_ref=1),string 'rua' (length=3)
2 => (refcount=1, is_ref=0),string 'toru' (length=4)

copyOfNumbers[1] changed

numbers:
(refcount=1, is_ref=0),
array (size=3)
0 => (refcount=2, is_ref=0),string 'tahi' (length=4)
1 => (refcount=3, is_ref=1),string 'two' (length=3)
2 => (refcount=2, is_ref=0),string 'toru' (length=4)
refToSecondElement:
(refcount=3, is_ref=1),string 'two' (length=3)
copyOfNumbers:
(refcount=1, is_ref=0),
array (size=3)
0 => (refcount=2, is_ref=0),string 'tahi' (length=4)
1 => (refcount=3, is_ref=1),string 'two' (length=3)
2 => (refcount=2, is_ref=0),string 'toru' (length=4)

copyOfNumbers[2] changed

numbers:
(refcount=1, is_ref=0),
array (size=3)
0 => (refcount=2, is_ref=0),string 'tahi' (length=4)
1 => (refcount=3, is_ref=1),string 'two' (length=3)
2 => (refcount=1, is_ref=0),string 'toru' (length=4)
refToSecondElement:
(refcount=3, is_ref=1),string 'two' (length=3)
copyOfNumbers:
(refcount=1, is_ref=0),
array (size=3)
0 => (refcount=2, is_ref=0),string 'tahi' (length=4)
1 => (refcount=3, is_ref=1),string 'two' (length=3)
2 => (refcount=1, is_ref=0),string 'three' (length=5)


Observations:

  • each variable and array element has a refcount and and is_ref.
  • When $numbers is first created, it's refcount is 1 (itself), and its is_ref is false. Fair enough.
  • When $refToSecondElement is made, $numbers refcount and is_ref don't change, but note that its second element now has a refcount of two (itself and $refToSecondElement), and it not states is_ref=1. So not only is $refToSecondElement a reference, so is $numbers[1].
  • When $copyOfNumbers is made, initially it's just a reference. Note the refcount on both reflects this, but the is_ref does not. I guess this is because there's a difference between how PHP handles value copying internally is distinct from actively creating references. Not sure.
  • Also note that the refcount on $refToSecondElement (and $numbers[1] and $copyOfNumbers[1]) still reflect two references. As $copyOfNumbers is itself a reference at this point, $numbers[1] and $copyOfNumbers[1] are exactly the same thing. Not a new reference.
  • Now $copyOfNumbers[1] changes, so PHP has to actually make $copyOfNumbers a copy now, not just a reference back to $numbers. This is an example of copy-on-write, and is a performance optimisation. If all one is doing is reading a copied value, then leaving it as a reference is fine. It's not until the copied data changes that it needs to take on life of its own. And this is borne out by the fact that $numbers and $copyOfNumbers now have a refcount of one apiece.
  • On the other hand, the refcount on $numbers[1], $refToSecondElement and $copyOfNumbers[1] is now three, because $copyOfNumbers[1] is now a separate reference from $numbers[1] .
  • Also note that - as one would expect - the value change to $copyOfNumbers[1] is reflected in $referenceToSecondElement too. And indeed back to the reference in $numbers[1] too. This latter bit is the thing we didn't initially expect, but it kinda makes sense now.
  • Lastly we change $copyOfNumbers[2], and we see the refcount for it and $numbers[2] decrement, because again we are seeing copy-on-write: PHP has ceased using a reference to $numbers[2] for $copyOfNumbers[2], and it's now its own value.

XDebug came in handy here demonstrating what's going on, and being able to see how the values / references change as values are changed.

I feel just that slight bit less ignorant about how PHP works now. Nice one.

--
Adam
(Tue, 30 Sep 2014 17:52:53 GMT)
[view article in new window]


© The connection to the COLDFUSIONBLOGGERS's RSS feed has timed out - please try again later. We are sorry for any inconvenience this may have caused.