PHP
PHP7

PHPの無名関数って何?


無名関数は、関数名のない関数のことです。


無名関数はクロージャとも呼ばれ、 関数名を指定せずに関数を作成できるようにするものです。 コールバック パラメータとして使う際に便利ですが、用途はそれにとどまりません。

PHP: 無名関数 - Manual


PHPでは、「無名関数」「ラムダ関数」「匿名関数」が同じものを指す・・・らしい。


無名関数をコールバックで使うパターン


WhatMumeiKansu.php

<?php

namespace App;

/**
* PHPの無名関数って何?.
*/

class WhatMumeiKansu
{
/** @var string スネークケースの区切り文字. */
const SNAKE_DELIMITER = '_';

/*
* パスカルケース文字列を大文字のスネークケース文字列へ変換する.
* @param array $pascals パスカルケース文字列.
* @return array 大文字のスネークケース文字列.
*/

public function convertStringToUpperSnakeCase(array $pascals): array
{
// 無名関数をコールバックで使うパターン.
return array_map(function ($pascal) {
$snake = preg_replace_callback('([A-Z])', function($matches) {
return self::SNAKE_DELIMITER.$matches[0];
}, $pascal);

if (mb_substr($snake, 0, 1) === self::SNAKE_DELIMITER) {
$snake = ltrim($snake, self::SNAKE_DELIMITER);
}
return strtoupper($snake);
}, $pascals);
}
}

$pascals = [
'PonsukeTarou',
'ponsukeTarou',
'Ponsuketarou'
];
$what = new WhatMumeiKansu();
var_dump($what->convertStringToUpperSnakeCase($pascals));


$ php src/WhatMumeiKansu.php 

array(3) {
[0]=>
string(13) "PONSUKE_TAROU"
[1]=>
string(13) "PONSUKE_TAROU"
[2]=>
string(12) "PONSUKETAROU"


無名関数を変数に代入するパターン


WhatMumeiKansu.php

<?php

// 無名関数を変数に代入する.
$toPascalCase = function($snake)
{
$lowerSnakeCase = strtolower($snake);
$upperCamelCase = ucwords($lowerSnakeCase, '_');
return str_replace('_', '', $upperCamelCase);
};

var_dump($toPascalCase('ponsuke_tarou'));

$snakeStrings = [
'ponsuke_tarou',
'PONSUKE_TAROU',
'poNSUKE_TARou'
];

// 無名関数を代入した変数をコールバックで使う.
var_dump(array_map($toPascalCase, $snakeStrings));


$ php WhatMumeiKansu.php 

string(12) "PonsukeTarou"
array(3) {
[0]=>
string(12) "PonsukeTarou"
[1]=>
string(12) "PonsukeTarou"
[2]=>
string(12) "PonsukeTarou"
}


class内で無名関数をプロパティに代入するとFatal error: Constant expression contains invalid operationsになります。


WhatMumeiKansu.php

<?php

/**
* PHPの無名関数って何?.
*/

class WhatMumeiKansu
{
/** @var string スネークケースの区切り文字. */
private const SNAKE_DELIMITER = '_';

/** @var Closure $toPacalCas スネークケース文字列をパスカルケース文字列にする. */
$toPascalCase = function($snake)
{
// 無名関数を変数に代入するパターン
$lowerSnakeCase = strtolower($snake);
$upperCamelCase = ucwords($lowerSnakeCase, self::SNAKE_DELIMITER);
return str_replace(self::SNAKE_DELIMITER, '', $upperCamelCase);
};
}

$what = new WhatMumeiKansu();
var_dump($what->toPascalCase('ponsuke_tarou'));


$ php WhatMumeiKansu.php 

PHP Fatal error: Constant expression contains invalid operations in /path/to/WhatMumeiKansu.php on line 11

Fatal error: Constant expression contains invalid operations in /path/to/WhatMumeiKansu.php on line 11


原因は、クラスのプロパティとメソッドは別々の名前空間にいるからです。


プロパティとメソッド

クラスのプロパティとメソッドは、それぞれ別の名前空間に存在するので、 同じ名前のプロパティとメソッドを共存させることもできます。 プロパティを参照する場合もメソッドを参照する場合も書きかたは同じです。 それがプロパティへのアクセスなのかメソッドの呼び出しなのかは、そのコンテキストによって決まります。 つまり、変数にアクセスしようとしているのか関数を呼び出そうとしているのかの違いです。

これはつまり、プロパティに 無名関数 を代入した場合に、その関数は直接呼び出せないということです。 その場合は、たとえば事前にプロパティを変数に代入しておく必要があります。

PHP: クラスの基礎 - Manual



class内で無名関数をプロパティに代入する場合はコンストラクタで代入します。


WhatMumeiKansu.php

<?php

namespace App;

/**
* PHPの無名関数って何?.
*/

class WhatMumeiKansu
{
/** @var string スネークケースの区切り文字. */
private const SNAKE_DELIMITER = '_';

/** @var Closure $toPacalCas スネークケース文字列をパスカルケース文字列にする. */
public $toPascalCase;

/**
* コンストラクタ.
*/

public function __construct()
{
// コンストラクタでプロパティに無名関数を代入する.
$this->toPascalCase = function($snake)
{
// 無名関数を変数に代入するパターン
$lowerSnakeCase = strtolower($snake);
$upperCamelCase = ucwords($lowerSnakeCase, self::SNAKE_DELIMITER);
return str_replace(self::SNAKE_DELIMITER, '', $upperCamelCase);
};
}

/**
* スネークケース文字列の配列をパスカルケース文字列の配列へ変換する.
* @param array $snakes スネークケース文字列の配列.
* @return array パスカルケース文字列の配列.
*/

function convertStringsToPascalCase(array $snakes): array
{
// 無名関数を代入した変数をコールバックで使うパターン.
return array_map($this->toPascalCase, $snakes);
}

/*
* パスカルケース文字列を大文字のスネークケース文字列へ変換する.
* @param array $pascals パスカルケース文字列.
* @return array 大文字のスネークケース文字列.
*/

public function convertStringToUpperSnakeCase(array $pascals): array
{
// 無名関数をコールバックで使うパターン.
return array_map(function ($pascal) {
$snake = preg_replace_callback('([A-Z])', function($matches) {
return self::SNAKE_DELIMITER.$matches[0];
}, $pascal);

if (mb_substr($snake, 0, 1) === self::SNAKE_DELIMITER) {
$snake = ltrim($snake, self::SNAKE_DELIMITER);
}
return strtoupper($snake);
}, $pascals);
}
}

$what = new WhatMumeiKansu();

var_dump(($what->toPascalCase)('ponsuke_tarou'));

$pascals = [
'PonsukeTarou',
'ponsukeTarou',
'Ponsuketarou'
];

var_dump(
$what->convertStringsToPascalCase(
$what->convertStringToUpperSnakeCase($pascals)
)
);


$ php WhatMumeiKansu.php 

string(12) "PonsukeTarou"
array(3) {
[0]=>
string(12) "PonsukeTarou"
[1]=>
string(12) "PonsukeTarou"
[2]=>
string(12) "Ponsuketarou"
}