Preface
Goal: Learning PHP without HTML burden.
A practical case to collect unique record fields using PHP.
You can use PHP in CLI as well.
Reference Reading
The last time I read php documentation seriously, was in 2011 (a decade ago). There have been some changes, and interesting things.
Source Examples
You can obtain source examples here:
Common Use Case
Task: Get the unique tag string
Please read overview for more detail.
Prepopulated Data
Songs and Poetry
We can use PHP class.
<?php
class MySong {
public function __construct(
public String $title = "",
public Array $tags = []
) {}
}
$songs = [
new MySong(
'Cantaloupe Island', ['60s', 'jazz']),
new MySong('Let It Be', ['60s', 'rock']),
new MySong(
'Knockin\' on Heaven\'s Door',
['70s', 'rock']),
new MySong('Emotion', ['70s', 'pop']),
new MySong('The River'),
];
__
PHP Solution
The Answer
I use list comprehension a lot. One of them is this oneliner as below:
<?php
require_once(__DIR__.'/MyClassSongs.php');
$tags =
array_values(
array_unique(
array_merge(
... array_map(
function ($song) {
return $song->tags; },
$songs)
)));
printf("%s\n", json_encode($tags));
Enough with introduction, at this point we should go straight to coding.
Environment
No need any special setup. Just run and voila..!
1: Data Structure Using Associative array
We are going to use associative array
,
throught out this article.
Simple Array
We can dump array
with these option:
- var_export()
- print_r()
- var_dump()
- echo json_encode()
We are going to compare this. The choice is yours to choose.
Consider begin with simple array
.
<?php
$tags = ["rock", "jazz", "rock", "pop", "pop"];
Then compare one by one:
var_export($tags);
print_r($tags);
var_dump($tags);
echo json_encode($tags);var_export($tags);
The last one, would result output similar to oneliner below:
❯ php 01-tags-d.php
["rock","jazz","rock","pop","pop"]
Associative Array
You can read about associative array in official documentation.
Consider this form.
<?php
$song = [ 'title' => 'Cantaloupe Island',
'tags' => ['60s', 'jazz'] ];
We can output with printf
for prettier output
printf("%s: [%s]\n",
$song['title'],
join(', ', $song['tags']));
With the result as below:
❯ php 02-record-a.php
Cantaloupe Island: [60s, jazz]
Or we can use previous form using json_encode
.
echo json_encode($song)."\n";
With the result as below:
❯ php 02-record-b.php
{"title":"Cantaloupe Island","tags":["60s","jazz"]}
The Songs Structure
We can continue our journey to records just using dictionary
.
No need any complex structure.
<?php
$songs = [
[ 'title' => 'Cantaloupe Island',
'tags' => ['60s', 'jazz'] ],
[ 'title' => 'Let It Be',
'tags' => ['60s', 'rock'] ],
[ 'title' => 'Knockin\' on Heaven\'s Door',
'tags' => ['70s', 'rock'] ],
[ 'title' => 'Emotion',
'tags' => ['70s', 'pop'] ],
[ 'title' => 'The River'],
];
foreach($songs as $song) {
printf("%s\n", json_encode($song));
}
With the result similar as below record:
❯ php 03-songs.php
{"title":"Cantaloupe Island","tags":["60s","jazz"]}
{"title":"Let It Be","tags":["60s","rock"]}
{"title":"Knockin' on Heaven's Door","tags":["70s","rock"]}
{"title":"Emotion","tags":["70s","pop"]}
{"title":"The River"}
2: Separating Module
Since we need to reuse the songs record multiple times, it is a good idea to separate the record structure from logic.
Songs Module
The code can be shown as below:
<?php
$songs = [
[ 'title' => 'Cantaloupe Island',
'tags' => ['60s', 'jazz'] ],
[ 'title' => 'Let It Be',
'tags' => ['60s', 'rock'] ],
[ 'title' => 'Knockin\' on Heaven\'s Door',
'tags' => ['70s', 'rock'] ],
[ 'title' => 'Emotion',
'tags' => ['70s', 'pop'] ],
[ 'title' => 'The River'],
];
Using Songs Module
Now we can have a very short code.
<?php
require_once(__DIR__.'/MySongs.php');
foreach($songs as $song) {
printf("%s\n", json_encode($song));
}
Or alternatively:
<?php
require_once(__DIR__.'/MySongs.php');
array_walk($songs, function($song) {
printf("%s\n", json_encode($song));
});
With the result as below associative array
.
❯ php 04-module-b.php
{"title":"Cantaloupe Island","tags":["60s","jazz"]}
{"title":"Let It Be","tags":["60s","rock"]}
{"title":"Knockin' on Heaven's Door","tags":["70s","rock"]}
{"title":"Emotion","tags":["70s","pop"]}
{"title":"The River"}
3: Finishing The Task
Extract, Flatten, Unique
Extracting Data Structure
There are choices.
Consider this four different approaches:
<?php
require_once(__DIR__.'/MySongs.php');
$tagss = [];
foreach($songs as $song) {
if(array_key_exists('tags', $song))
$tagss[] = $song['tags'];
}
printf("%s\n", json_encode($tagss));
Alternatively we can obtain $tagss
using this code below
<?php
function walk($song) {
return isset($song['tags']) ?
$song['tags'] : null;
}
$tagss = array_map('walk', $songs);
Or maybe this one is your preferred choice.
<?php
$songs = array_filter($songs, function ($song) {
return isset($song['tags']);
});
$tagss = array_map(function ($song) {
return $song['tags'];
}, $songs);
We can even write the last one as oneliner below:
<?php
$tagss = array_map(
function ($song) { return $song['tags']; },
array_filter($songs, function ($song) {
return array_key_exists('tags', $song);
})
);
With the result of array
of array
, as shown below.
❯ php 05-extract-ca.php
[["60s","jazz"],["60s","rock"],["70s","rock"],["70s","pop"]]
The choice is yours.
Flatten
There are also choices.
Consider this three different approaches:
The first is utilizing ...
feature.
<?php
require_once(__DIR__.'/MySongs.php');
$tagss = [];
foreach($songs as $song) {
if(array_key_exists('tags', $song))
$tagss[] = $song['tags'];
}
$tags = array_merge(...$tagss);
printf("%s\n", json_encode($tags));
With the result of a flattened array
shown below.
❯ php 06-flatten-a.php
["60s","jazz","60s","rock","70s","rock","70s","pop"]
We can rewrite above statement,
using array_walk_recursive
.
<?php
require_once(__DIR__.'/MySongs.php');
$tagss = [];
foreach($songs as $song) {
if(array_key_exists('tags', $song))
$tagss[] = $song['tags'];
}
function flatten(array $tagss) {
$tags = array();
array_walk_recursive(
$tagss,
function($element) use (&$tags) {
$tags[] = $element;
}
);
return $tags;
}
printf("%s\n", json_encode(flatten($tagss)));
Or maybe just flattening form the very start. This way should be more efficent.
<?php
require_once(__DIR__.'/MySongs.php');
$tags = [];
foreach($songs as $song) {
if(array_key_exists('tags', $song))
foreach($song['tags'] as $tag) {
$tags[] = $tag;
}
}
printf("%s\n", json_encode($tags));
With the result exactly the same as previous flattened array
.
Unique
To solve unique
array,
we can just use the array_unique
function.
<?php
require_once(__DIR__.'/MySongs.php');
$tagss = [];
foreach($songs as $song) {
if(array_key_exists('tags', $song))
$tagss[] = $song['tags'];
}
$tags =
array_values(
array_unique(
array_merge(
...$tagss
)));
printf("%s\n", json_encode($tags));
With the result similar as below array:
❯ php 07-unique.php
["60s","jazz","rock","70s","pop"]
I can live with that.
What is Next 🤔?
We have alternative way to build the record structure.
Consider continue reading [ PHP - Playing with Records - Part Two ].