1: <?php
2: /*
3: * Copyright (c) 2014 @trashtoy
4: * https://github.com/trashtoy/
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy of
7: * this software and associated documentation files (the "Software"), to deal in
8: * the Software without restriction, including without limitation the rights to use,
9: * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10: * Software, and to permit persons to whom the Software is furnished to do so,
11: * subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in all
14: * copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18: * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19: * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20: * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21: * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22: */
23: /**
24: * PHP class file.
25: * @auhtor trashtoy
26: * @since 2.0.0
27: */
28: namespace Peach\Util;
29:
30: /**
31: * デフォルトのコンパレータです.
32: * {@link Arrays::sort} などのメソッドで,
33: * 引数にコンパレータが指定されなかった場合に適用されます.
34: */
35: class DefaultComparator implements Comparator
36: {
37: /**
38: * 二つの値を比較します.
39: * $var1 === $var2 の場合は 0 を返します.
40: *
41: * @param mixed $var1
42: * @param mixed $var2
43: */
44: public function compare($var1, $var2)
45: {
46: if ($var1 === $var2) {
47: return 0;
48: }
49: if (is_object($var1) || is_object($var2)) {
50: return self::compareObjects($var1, $var2);
51: }
52: if (is_array($var1) || is_array($var2)) {
53: return self::compareArrays($var1, $var2);
54: }
55: if (is_string($var1) || is_string($var2)) {
56: return strcmp($var1, $var2);
57: }
58: if ($var1 == $var2) {
59: return self::compareTypes($var1, $var2);
60: }
61:
62: return ($var1 > $var2) ? 1 : -1;
63: }
64:
65: /**
66: * var_dump の出力から, 冒頭の object(#x) 部分を除いた文字列を返します.
67: *
68: * @param mixed $var
69: * @return string オブジェクトの文字列表現
70: */
71: private static function dump($var)
72: {
73: ob_start();
74: var_dump($var);
75: $data = ob_get_contents();
76: ob_end_clean();
77:
78: $classNamePattern = "([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9\\\\_\\x7f-\\xff]*)";
79:
80: // xdebug の設定によって処理が変わるため, コードカバレージの対象外とします
81: // @codeCoverageIgnoreStart
82: if (preg_match("/^object\\({$classNamePattern}\\)#(\\d+)/", $data)) {
83: return preg_replace("/^object\\({$classNamePattern}\\)#(\\d+)/", "$1", $data);
84: }
85: if (preg_match("/^class {$classNamePattern}#(\\d+)/", $data)) {
86: return preg_replace("/^class {$classNamePattern}#(\\d+)/", "$1", $data);
87: }
88: return $data;
89: // @codeCoverageIgnoreEnd
90: }
91:
92: /**
93: * 引数のオブジェクトを比較します.
94: * 引数のうち, 少なくとも一方が {@link Comparable} を実装していた場合,
95: * そのオブジェクトの compareTo の結果を返します.
96: * それ以外の場合は var_dump の結果を文字列比較して大小を判定します.
97: *
98: * @param mixed $var1
99: * @param mixed $var2
100: * @return int
101: */
102: private static function compareObjects($var1, $var2)
103: {
104: if ($var1 instanceof Comparable) {
105: return $var1->compareTo($var2);
106: }
107: if ($var2 instanceof Comparable) {
108: return $var2->compareTo($var1) * (-1);
109: }
110: $str1 = self::dump($var1);
111: $str2 = self::dump($var2);
112: return strcmp($str1, $str2);
113: }
114:
115: /**
116: * 引数 $var1 と $var2 を比較し, 結果を 0, 1, -1 のいずれかで返します.
117: *
118: * @param mixed $var1 比較対象の値
119: * @param mixed $var2 比較対象の値
120: * @return int 引数 $var1 のほうが大きい場合は 1, $var2 のほうが大きい場合は -1, 等しい場合は 0
121: */
122: private static function compareArrays($var1, $var2)
123: {
124: if ($var1 == $var2) {
125: return 0;
126: }
127:
128: return ($var1 > $var2) ? 1 : -1;
129: }
130:
131: /**
132: * 異なる値 $var1, $var2 について,
133: * 一方が NULL や FALSE などの値だった場合の大小関係を定義します.
134: * この実装は NULL < FALSE < その他 という順序付けをします.
135: *
136: * @param mixed $var1
137: * @param mixed $var2
138: * @return int 比較結果が等しい場合は 0, $var1 > $var2 の場合は 1, それ以外は -1
139: */
140: private static function compareTypes($var1, $var2)
141: {
142: if ($var1 === null) {
143: return -1;
144: }
145: if ($var2 === null) {
146: return 1;
147: }
148: if (is_bool($var1)) {
149: return -1;
150: }
151: if (is_bool($var2)) {
152: return 1;
153: }
154:
155: return 0;
156: }
157:
158: /**
159: * このクラスはインスタンス化できません.
160: */
161: private function __construct() {}
162:
163: /**
164: * 唯一のインスタンスを返します.
165: *
166: * @return DefaultComparator
167: * @codeCoverageIgnore
168: */
169: public static function getInstance()
170: {
171: static $instance = null;
172: if (!isset($instance)) {
173: $instance = new self();
174: }
175: return $instance;
176: }
177: }
178: