is_xxx() 関数を使わずに型判定できますか?
問題
\CarrotRakko
という名前空間の直下に以下の8つの関数を定義せよ。定義する関数のシグネチャと外から見た挙動は、グローバル名前空間に存在する同名の関数と同じにすること。
関数/メソッド呼び出しは行なってはならない。ここで、関数/メソッドの呼び出しとはPHP処理系の実装レベルで関数/メソッドがコールされることを指すのであって、PHPコードでの呼び出し方は問わない。なお、以下のソースコードでは関数/メソッド呼び出しを行わずに実装できる部分を、関数/メソッド呼び出しによって簡潔に表現することがある。
実装に用いる言語およびバージョンは PHP 7.4.x とする。公式でない処理系や標準でバンドルされていないエクステンション、自作のエクステンションの使用などは認めない。
問1: is_bool(mixed $var): bool
問2: is_int(mixed $var): bool
問3: is_float(mixed $var): bool
問4: is_string(mixed $var): bool
問5: is_array(mixed $var): bool
問6: is_object(mixed $var): bool
問7: is_resource(mixed $var): bool
問8: is_null(mixed $var): bool
問1: is_bool(mixed $var): bool
最初に思いついたのは次のような実装です。
<?php
namespace CarrotRakko;
/**
* boolean型かどうか
*
* @param mixed $var
* @return bool
*/
function is_bool($var): bool
{
return ($var === true) || ($var === false);
}
boolean型 には true
と false
の2値しかないのでこういうことができます。しかしながら、型の中には取りうる値が有限個ではないもの( string型, array型, object型, resource型 )や、有限個ではあるがリテラルをベタがきするには多すぎるもの( int型, float型 )があるため、boolean型 の値の種類の少なさに依存しない実装をしてみたいところです。
function is_bool($var): bool
{
return !!$var === $var;
}
ここで 論理否定演算子(Logical Not Operator) について確認しておきたいと思います。 !$var
が評価されるときはまず、 $var
が boolean型に変換 されます。変換された結果が true
であれば !$var
は false
に、 false
であれば !$var
は true
に評価されます。
論理否定演算子の確認が済んだところで、 booleanへの変換(Converting to boolean)を理解しましょう。リンク先を読むと、PHPの8つの型はいずれもboolean型に変換できることがわかります。
ここで、 !
を使って実装した is_bool(mixed $var): bool
関数が正しい挙動をすることを証明できるようになりました。 !!$var
は常にboolean型なので、 $var
がboolean型ではないときには !!$var === $var
は false
に評価されます。 $var
が true
のときも false
のときも !!$var === $var
は true
に評価されるので、この関数の挙動が正しいことを証明できました。
!!
してから元々の値と比較するというような便利なことは他の型ではできそうにないので、もうちょっと一般化しておきましょう。
function is_bool($var): bool
{
return (bool)$var === $var;
}
問2: is_int(mixed $var): bool
整数への変換(Converting to integer)を読むと、boolean型, int型, float型, string型, resource型, null型の6つの型はint型に変換できるようです。array型, object型の2つの型をint型に変換しようとしたときの挙動は未定義と書いてあります。
循環呼び出しにならないように is_array()
, is_object()
を定義できると期待すると、次のような実装ができます。
<?php
namespace CarrotRakko;
/**
* int型かどうか
*
* @param mixed $var
* @return bool
*/
function is_int($var): bool
{
return !is_array($var)
&& !is_object($var)
&& (int)$var === $var;
}
問3: is_float(mixed $var): bool
float への変換(Converting to float)を読むと、float型への変換が定義されている型とint型への変換が定義されている型は同じことがわかります。したがって、 is_int()
を実装したときと同じ期待のもとで次のような実装が可能です。float型には NAN
という NAN !== NAN
な値があることに注意が必要です。
<?php
namespace CarrotRakko;
/**
* float型かどうか
*
* @param mixed $var
* @return bool
*/
function is_float($var): bool
{
return !is_array($var)
&& !is_object($var)
&& (
(float)$var === $var
|| $var !== $var
);
}
問4: is_string(mixed $var): bool
文字列への変換(Converting to string)を読みましょう。array型とobject型があやしいので実験してみます。
(string)[];
// => PHP Notice: Array to string conversion
(string)(new class() {});
// => PHP Fatal error: Uncaught Error: Object of class class@anonymous could not be converted to string
諦めて is_int()
, is_float()
と同様の実装をします。
<?php
namespace CarrotRakko;
/**
* string型かどうか
*
* @param mixed $var
* @return bool
*/
function is_string($var): bool
{
return !is_array($var)
&& !is_object($var)
&& (string)$var === $var;
}
問5: is_array(mixed $var): bool
配列への変換(Converting to array)を読むと、8つの型はいずれもarray型に変換できるので、次の実装ができます。
<?php
namespace CarrotRakko;
/**
* array型かどうか
*
* @param mixed $var
* @return bool
*/
function is_array($var): bool
{
return (array)$var === $var;
}
問6: is_object(mixed $var): bool
オブジェクトへの変換(Converting to object)を読むと、8つの型はいずれもobject型に変換できるので、次の実装ができます。
<?php
namespace CarrotRakko;
/**
* object型かどうか
*
* @param mixed $var
* @return bool
*/
function is_object($var): bool
{
return (object)$var === $var;
}
問7: is_resource(mixed $var): bool
リソースへの変換(Converting to resource)を読むと、resource型に関しては今までと同じ戦略が通用しそうにありません。循環呼び出しにならないように is_null()
を定義できる自信があるので、次のような実装でゴリ押します。
<?php
namespace CarrotRakko;
/**
* resource型かどうか
*
* @param mixed $var
* @return bool
*/
function is_resource($var): bool
{
return !is_bool($var)
&& !is_int($var)
&& !is_float($var)
&& !is_string($var)
&& !is_array($var)
&& !is_object($var)
&& !is_null($var);
}
問8: is_null(mixed $var): bool
遊ぶ順番を間違えた感...。
<?php
namespace CarrotRakko;
/**
* null型かどうか
*
* @param mixed $var
* @return bool
*/
function is_null($var): bool
{
return null === $var;
}
展望
関数を実装してみたはいいものの、エラーを吐かないかどうかや、挙動がビルトインの関数と同じかのテストをする必要があるなと思っています。
また、PHPには8つの型を判定する関数以外にも is_xxx()
な名前の関数があるので、挙動を理解して再発明してみたいですね。
問9: is_a
問10: is_callable
問11: is_countable
問12: is_finite
問13: is_infinite
問14: is_iterable
問15: is_nan
問16: is_numeric
問17: is_scalar
問18: is_subclass_of
Author And Source
この問題について(is_xxx() 関数を使わずに型判定できますか?), 我々は、より多くの情報をここで見つけました https://qiita.com/carrotRakko/items/2dc457674c9cd4552905著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .