1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Class Image |
4
|
|
|
* |
5
|
|
|
* @link https://www.icy2003.com/ |
6
|
|
|
* @author icy2003 <[email protected]> |
7
|
|
|
* @copyright Copyright (c) 2017, icy2003 |
8
|
|
|
*/ |
9
|
|
|
namespace icy2003\php\ihelpers; |
10
|
|
|
|
11
|
|
|
use Exception; |
12
|
|
|
use icy2003\php\C; |
13
|
|
|
use icy2003\php\I; |
14
|
|
|
use icy2003\php\icomponents\file\LocalFile; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* 图片处理类 |
18
|
|
|
*/ |
19
|
|
|
class Image |
20
|
|
|
{ |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* 加载图片 |
24
|
|
|
* |
25
|
|
|
* @param string $image 图片路径 |
26
|
|
|
* |
27
|
|
|
* @return void |
28
|
|
|
*/ |
29
|
|
|
public function __construct($image) |
30
|
|
|
{ |
31
|
|
|
$this->_attributes = $this->__parseImage($image); |
32
|
|
|
$this->_imageIn = $this->_attributes['object']; |
|
|
|
|
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* 输入图片对象 |
37
|
|
|
* |
38
|
|
|
* @var resource |
39
|
|
|
*/ |
40
|
|
|
protected $_imageIn; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* 输出图片对象 |
44
|
|
|
* |
45
|
|
|
* @var resource |
46
|
|
|
*/ |
47
|
|
|
protected $_imageOut; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* 图片属性 |
51
|
|
|
* |
52
|
|
|
* @var array |
53
|
|
|
*/ |
54
|
|
|
protected $_attributes = []; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* 解析图片属性 |
58
|
|
|
* |
59
|
|
|
* @param string $image 图片地址 |
60
|
|
|
* |
61
|
|
|
* @return array |
62
|
|
|
*/ |
63
|
|
|
private function __parseImage($image) |
64
|
|
|
{ |
65
|
|
|
$image = I::getAlias($image); |
66
|
|
|
C::assertTrue(is_array($size = @getimagesize($image)), '不是有效的图片:' . $image); |
|
|
|
|
67
|
|
|
// static::$_instance->_attributes['size'] = $size; |
68
|
|
|
$width = $size[0]; |
69
|
|
|
$height = $size[1]; |
70
|
|
|
$mime = $size['mime']; |
71
|
|
|
switch ($size[2]) { |
72
|
|
|
case 1: |
73
|
|
|
$ext = 'gif'; |
74
|
|
|
$object = imagecreatefromgif($image); |
75
|
|
|
$method = 'imagegif'; |
76
|
|
|
break; |
77
|
|
|
case 2: |
78
|
|
|
$ext = 'jpg'; |
79
|
|
|
$object = imagecreatefromjpeg($image); |
80
|
|
|
$method = 'imagejpeg'; |
81
|
|
|
break; |
82
|
|
|
case 3: |
83
|
|
|
$ext = 'png'; |
84
|
|
|
$object = imagecreatefrompng($image); |
85
|
|
|
$method = 'imagepng'; |
86
|
|
|
break; |
87
|
|
|
default: |
88
|
|
|
throw new Exception("不支持的图片类型"); |
89
|
|
|
} |
90
|
|
|
return [ |
91
|
|
|
'file' => $image, |
92
|
|
|
'width' => $width, |
93
|
|
|
'height' => $height, |
94
|
|
|
'mime' => $mime, |
95
|
|
|
'ext' => $ext, |
96
|
|
|
'object' => $object, |
97
|
|
|
'method' => $method, |
98
|
|
|
]; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* 获取图片属性数组 |
103
|
|
|
* |
104
|
|
|
* @return array |
105
|
|
|
*/ |
106
|
|
|
public function getAttributes() |
107
|
|
|
{ |
108
|
|
|
return $this->_attributes; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* 获取图片属性 |
113
|
|
|
* |
114
|
|
|
* @param string $name |
115
|
|
|
* |
116
|
|
|
* @return mixed |
117
|
|
|
*/ |
118
|
|
|
public function getAttribute($name) |
119
|
|
|
{ |
120
|
|
|
return I::get($this->_attributes, $name); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* 设置透明度 |
125
|
|
|
* |
126
|
|
|
* @return void |
127
|
|
|
*/ |
128
|
|
|
private function __setTransparency() |
129
|
|
|
{ |
130
|
|
|
$index = imagecolortransparent($this->_imageIn); |
131
|
|
|
$color = ['red' => 255, 'green' => 255, 'blue' => 255]; |
132
|
|
|
if ($index >= 0) { |
133
|
|
|
$color = imagecolorsforindex($this->_imageIn, $index); |
134
|
|
|
} |
135
|
|
|
null === $this->_imageOut && $this->_imageOut = imagecreatetruecolor($this->_attributes['width'], $this->_attributes['height']); |
|
|
|
|
136
|
|
|
$index = imagecolorallocate($this->_imageOut, $color['red'], $color['green'], $color['blue']); |
137
|
|
|
imagefill($this->_imageOut, 0, 0, $index); |
138
|
|
|
imagecolortransparent($this->_imageOut, $index); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* 缩放图片 |
143
|
|
|
* |
144
|
|
|
* @param array|integer $zoom 数组或数字,如:数组[1, 0.5]表示宽不变,高变成一半,如果是整数,表示等比例缩放 |
145
|
|
|
* |
146
|
|
|
* @return static |
147
|
|
|
*/ |
148
|
|
|
public function zoom($zoom = 1) |
149
|
|
|
{ |
150
|
|
|
if (2 === Arrays::count($zoom)) { |
151
|
|
|
list($zoomWidth, $zoomHeight) = $zoom; |
152
|
|
|
$zoomWidth *= $this->_attributes['width']; |
153
|
|
|
$zoomHeight *= $this->_attributes['height']; |
154
|
|
|
} else { |
155
|
|
|
$zoom = (int) $zoom; |
156
|
|
|
$zoomWidth = $zoom * $this->_attributes['width']; |
157
|
|
|
$zoomHeight = $zoom * $this->_attributes['height']; |
158
|
|
|
} |
159
|
|
|
if ($this->_imageOut = imagecreatetruecolor($zoomWidth, $zoomHeight)) { |
|
|
|
|
160
|
|
|
$this->__setTransparency(); |
161
|
|
|
imagecopyresampled($this->_imageOut, $this->_imageIn, 0, 0, 0, 0, $zoomWidth, $zoomHeight, $this->_attributes['width'], $this->_attributes['height']); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
return $this; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* 裁剪 |
169
|
|
|
* |
170
|
|
|
* @param array $cut 裁剪的宽高,如:[100, 200] |
171
|
|
|
* @param array $pos 裁剪起始 x 和 y 坐标,坐标原点在左上角,如:[0, 0] |
172
|
|
|
* |
173
|
|
|
* @return static |
174
|
|
|
*/ |
175
|
|
|
public function cut($cut = null, $pos = [0, 0]) |
176
|
|
|
{ |
177
|
|
|
null === $cut && $cut = [$this->_attributes['width'], $this->_attributes['height']]; |
178
|
|
|
$width = min($this->_attributes['width'], $cut[0]); |
179
|
|
|
$height = min($this->_attributes['height'], $cut[1]); |
180
|
|
|
$x = min($this->_attributes['width'], $pos[0]); |
181
|
|
|
$y = min($this->_attributes['height'], $pos[1]); |
182
|
|
|
if ($this->_imageOut = imagecreatetruecolor($width, $height)) { |
|
|
|
|
183
|
|
|
$this->__setTransparency(); |
184
|
|
|
imagecopy($this->_imageOut, $this->_imageIn, 0, 0, $x, $y, $this->_attributes['width'], $this->_attributes['height']); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
return $this; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* 创建文字水印 |
192
|
|
|
* |
193
|
|
|
* @param string $text 文字水印内容 |
194
|
|
|
* @param array $pos 水印位置,默认在左上角的坐标原点 |
195
|
|
|
* @param mixed $fontColor 颜色值,支持类型参见 Color |
196
|
|
|
* @param int $fontSize 字体大小,默认 12 |
197
|
|
|
* @param string $fontPath 字体路径,默认宋体 |
198
|
|
|
* |
199
|
|
|
* @return static |
200
|
|
|
*/ |
201
|
|
|
public function markText($text, $pos = [0, 0], $fontColor = 'black', $fontSize = 12, $fontPath = 'simkai') |
202
|
|
|
{ |
203
|
|
|
if ($this->_imageOut = imagecreatetruecolor($this->_attributes['width'], $this->_attributes['height'])) { |
|
|
|
|
204
|
|
|
$this->__setTransparency(); |
205
|
|
|
$text = Charset::toUtf($text); |
206
|
|
|
$temp = imagettfbbox($fontSize, 0, $fontPath, $text); |
207
|
|
|
$textWidth = $temp[2] - $temp[6]; |
208
|
|
|
// $textHeight = $temp[3] - $temp[7]; |
209
|
|
|
imagesettile($this->_imageOut, $this->_imageIn); |
210
|
|
|
imagefilledrectangle($this->_imageOut, 0, 0, $this->_attributes['width'], $this->_attributes['height'], IMG_COLOR_TILED); |
211
|
|
|
list($red, $green, $blue) = (new Color($fontColor))->toRGB()->get(); |
212
|
|
|
$text2 = imagecolorallocate($this->_imageOut, $red, $green, $blue); |
213
|
|
|
$posX = min($pos[0], $this->_attributes['width'] - $textWidth); |
214
|
|
|
$posY = min($pos[1], $this->_attributes['height']); |
215
|
|
|
imagettftext($this->_imageOut, $fontSize, 0, $posX, $posY, $text2, $fontPath, $text); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
return $this; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* 创建图片水印 |
223
|
|
|
* |
224
|
|
|
* @param string $image 图片水印的地址 |
225
|
|
|
* @param array $pos 水印位置,默认在左上角的坐标原点 |
226
|
|
|
* @param array $size 图片水印大小,如果不给则是默认大小 |
227
|
|
|
* |
228
|
|
|
* @return static |
229
|
|
|
*/ |
230
|
|
|
public function markPicture($image, $pos = [0, 0], $size = null) |
231
|
|
|
{ |
232
|
|
|
if ($this->_imageOut = imagecreatetruecolor($this->_attributes['width'], $this->_attributes['height'])) { |
|
|
|
|
233
|
|
|
$this->__setTransparency(); |
234
|
|
|
$markAttrs = $this->__parseImage($image); |
235
|
|
|
null === $size && $size = [$markAttrs['width'], $markAttrs['height']]; |
236
|
|
|
imagecopy($this->_imageOut, $this->_imageIn, 0, 0, 0, 0, $this->_attributes['width'], $this->_attributes['height']); |
237
|
|
|
$posX = min($pos[0], $this->_attributes['width'] - $size[0]); |
238
|
|
|
$posY = min($pos[1], $this->_attributes['height'] - $size[1]); |
239
|
|
|
imagecopyresized($this->_imageOut, /** @scrutinizer ignore-type */$markAttrs['object'], $posX, $posY, 0, 0, $size[0], $size[1], $markAttrs['width'], $markAttrs['height']); |
240
|
|
|
imagedestroy(/** @scrutinizer ignore-type */$markAttrs['object']); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
return $this; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* 沿着 Y 轴翻转 |
248
|
|
|
* |
249
|
|
|
* @return static |
250
|
|
|
*/ |
251
|
|
|
public function turnY() |
252
|
|
|
{ |
253
|
|
|
if ($this->_imageOut = imagecreatetruecolor($this->_attributes['width'], $this->_attributes['height'])) { |
|
|
|
|
254
|
|
|
for ($x = 0; $x < $this->_attributes['width']; $x++) { |
255
|
|
|
imagecopy($this->_imageOut, $this->_imageIn, $this->_attributes['width'] - $x - 1, 0, $x, 0, 1, $this->_attributes['height']); |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
return $this; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* 沿着 X 轴翻转 |
264
|
|
|
* |
265
|
|
|
* @return static |
266
|
|
|
*/ |
267
|
|
|
public function turnX() |
268
|
|
|
{ |
269
|
|
|
if ($this->_imageOut = imagecreatetruecolor($this->_attributes['width'], $this->_attributes['height'])) { |
|
|
|
|
270
|
|
|
for ($y = 0; $y < $this->_attributes['height']; $y++) { |
271
|
|
|
imagecopy($this->_imageOut, $this->_imageIn, 0, $this->_attributes['height'] - $y - 1, 0, $y, $this->_attributes['width'], 1); |
272
|
|
|
} |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
return $this; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* 逆时针旋转图片 |
280
|
|
|
* |
281
|
|
|
* @param integer $degrees 角度 |
282
|
|
|
* |
283
|
|
|
* @return static |
284
|
|
|
*/ |
285
|
|
|
public function rotate($degrees = -90) |
286
|
|
|
{ |
287
|
|
|
$this->_imageOut = imagerotate($this->_attributes['object'], $degrees, 0); |
|
|
|
|
288
|
|
|
$this->__setTransparency(); |
289
|
|
|
|
290
|
|
|
return $this; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* 获取 (x, y) 坐标处的颜色值 |
295
|
|
|
* |
296
|
|
|
* @param integer $x |
297
|
|
|
* @param integer $y |
298
|
|
|
* |
299
|
|
|
* @return \icy2003\php\ihelpers\Color Color 类对象 |
300
|
|
|
*/ |
301
|
|
|
public function getColor($x, $y) |
302
|
|
|
{ |
303
|
|
|
$rgb = imagecolorat($this->_attributes['object'], $x, $y); |
304
|
|
|
return new Color([($rgb >> 16) & 0xFF, ($rgb >> 8) & 0xFF, $rgb & 0xFF], Color::TYPE_RGB); |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
/** |
308
|
|
|
* 保存图片到某个路径下,文件名自动生成 |
309
|
|
|
* |
310
|
|
|
* @param string $path 目标路径 |
311
|
|
|
* |
312
|
|
|
* @return void |
313
|
|
|
*/ |
314
|
|
|
public function saveTo($path = './') |
315
|
|
|
{ |
316
|
|
|
$this->save($path . date('YmdHis') . '.' . $this->_attributes['ext']); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* 保存到文件,如果不给文件名,则保存回原文件 |
321
|
|
|
* |
322
|
|
|
* @return void |
323
|
|
|
*/ |
324
|
|
|
public function save($file = null) |
325
|
|
|
{ |
326
|
|
|
null === $file && $file = $this->_attributes['file']; |
327
|
|
|
$this->_attributes['out'] = $file; |
328
|
|
|
$method = $this->_attributes['method']; |
329
|
|
|
$method($this->_imageOut, $this->_attributes['out']); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* 显示图片到浏览器 |
334
|
|
|
* |
335
|
|
|
* @return void |
336
|
|
|
*/ |
337
|
|
|
public function show() |
338
|
|
|
{ |
339
|
|
|
header('Content-type:' . $this->_attributes['mime']); |
340
|
|
|
$method = $this->_attributes['method']; |
341
|
|
|
null === $this->_imageOut && $this->_imageOut = $this->_imageIn; |
342
|
|
|
$method($this->_imageOut); |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* 释放图片资源 |
347
|
|
|
* |
348
|
|
|
* @return void |
349
|
|
|
*/ |
350
|
|
|
public function destroy() |
351
|
|
|
{ |
352
|
|
|
is_resource($this->_imageIn) && imagedestroy($this->_imageIn); |
353
|
|
|
is_resource($this->_imageOut) && imagedestroy($this->_imageOut); |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* 生成验证码 |
358
|
|
|
* |
359
|
|
|
* @todo 智能处理文字和图片间距大小等 |
360
|
|
|
* |
361
|
|
|
* @param string $code 验证码 |
362
|
|
|
* @param array $size 验证码图片宽高,默认 80*30 |
363
|
|
|
* @param int $fontSize 字体大小,默认 14 |
364
|
|
|
* @param string $fontPath 字体路径,默认宋体 |
365
|
|
|
* @param int $pixelNum 杂点数量,默认 2 |
366
|
|
|
* @param int $pixelColor 杂点颜色数量,默认 5 |
367
|
|
|
* @param int $padding 文字左右间距 |
368
|
|
|
* @param int $margin 文字左边距 |
369
|
|
|
* @param int $base 文字上边距 |
370
|
|
|
* @param int $baseOffset 文字抖动偏差 |
371
|
|
|
* |
372
|
|
|
* @return void |
373
|
|
|
*/ |
374
|
|
|
public static function captcha($code, $size = [80, 30], $fontSize = 14, $fontPath = 'simkai', $pixelNum = 2, $pixelColor = 5, $padding = 8, $margin = 7, $base = 20, $baseOffset = 4) |
375
|
|
|
{ |
376
|
|
|
header("Cache-Control: no-cache, must-revalidate"); |
377
|
|
|
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); |
378
|
|
|
header("Pragma: no-cache"); |
379
|
|
|
header("Cache-control: private"); |
380
|
|
|
header('Content-Type: image/png'); |
381
|
|
|
$codeLength = Strings::length($code); |
382
|
|
|
if ($image = imagecreatetruecolor($size[0], $size[1])) { |
383
|
|
|
imagefilledrectangle($image, 0, 0, $size[0] - 1, $size[1] - 1, imagecolorallocate($image, mt_rand(235, 255), mt_rand(235, 255), mt_rand(235, 255))); |
384
|
|
|
for ($i = 0; $i < $pixelColor; $i++) { |
385
|
|
|
$noiseColor = imagecolorallocate($image, mt_rand(150, 225), mt_rand(150, 225), mt_rand(150, 225)); |
386
|
|
|
for ($j = 0; $j < $pixelNum; $j++) { |
387
|
|
|
imagestring($image, 1, mt_rand(-10, $size[0]), mt_rand(-10, $size[1]), Strings::random(1), $noiseColor); |
388
|
|
|
} |
389
|
|
|
} |
390
|
|
|
$codeArray = Strings::split($code); |
391
|
|
|
for ($i = 0; $i < $codeLength; ++$i) { |
392
|
|
|
$color = imagecolorallocate($image, mt_rand(0, 100), mt_rand(20, 120), mt_rand(50, 150)); |
393
|
|
|
imagettftext($image, $fontSize, mt_rand(-10, 10), $margin, mt_rand($base - $baseOffset, $base + $baseOffset), $color, $fontPath, $codeArray[$i]); |
394
|
|
|
$margin += (imagefontwidth($fontSize) + $padding); |
395
|
|
|
} |
396
|
|
|
imagepng($image); |
397
|
|
|
imagedestroy($image); |
398
|
|
|
} |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
/** |
402
|
|
|
* 猫咪图片 |
403
|
|
|
*/ |
404
|
|
|
const RESOURCE_CAT = 'http://placekitten.com'; |
405
|
|
|
|
406
|
|
|
/** |
407
|
|
|
* 图片 |
408
|
|
|
*/ |
409
|
|
|
const RESOURCE_DEFAULT = 'https://picsum.photos'; |
410
|
|
|
|
411
|
|
|
/** |
412
|
|
|
* 文字图片 |
413
|
|
|
*/ |
414
|
|
|
const RESOURCE_PLAINTEXT = 'https://fakeimg.pl'; |
415
|
|
|
|
416
|
|
|
/** |
417
|
|
|
* 生成随机图片并返回图片路径 |
418
|
|
|
* |
419
|
|
|
* @param string $dir 目标目录 |
420
|
|
|
* @param array $options 选项 |
421
|
|
|
* - width:图片宽,默认 120 |
422
|
|
|
* - height:图片高,默认 120 |
423
|
|
|
* - resource:图片服务 |
424
|
|
|
* -- self::RESOURCE_DEFAULT 默认 |
425
|
|
|
* -- self::RESOURCE_PLAINTEXT 纯文字:text 文字内容 |
426
|
|
|
* -- self::RESOURCE_CAT 猫咪 |
427
|
|
|
* |
428
|
|
|
* @return string |
429
|
|
|
*/ |
430
|
|
|
public static function randomTo($dir, $options = []) |
431
|
|
|
{ |
432
|
|
|
$options['resource'] = I::get($options, 'resource', self::RESOURCE_DEFAULT); |
433
|
|
|
$options['width'] = I::get($options, 'width', 120); |
434
|
|
|
$options['height'] = I::get($options, 'height', 120); |
435
|
|
|
$url = $options['resource']; |
436
|
|
|
if (self::RESOURCE_PLAINTEXT === $options['resource']) { |
437
|
|
|
$url .= '/' . $options['width'] . 'x' . $options['height']; |
438
|
|
|
$url .= '/?text=' . I::get($options, 'text'); |
439
|
|
|
$url .= '&font=noto'; |
440
|
|
|
} else if (self::RESOURCE_DEFAULT === $options['resource']) { |
441
|
|
|
$url .= '/' . $options['width'] . '/' . $options['height']; |
442
|
|
|
$query = []; |
443
|
|
|
if (isset($options['grayscale'])) { |
444
|
|
|
$query['grayscale'] = 1; |
445
|
|
|
} |
446
|
|
|
if (isset($options['blur'])) { |
447
|
|
|
$query['blur'] = 1; |
448
|
|
|
} |
449
|
|
|
if (isset($options['random'])) { |
450
|
|
|
$query['random'] = 1; |
451
|
|
|
} |
452
|
|
|
} else { |
453
|
|
|
$url .= '/' . $options['width'] . '/' . $options['height']; |
454
|
|
|
} |
455
|
|
|
$fileName = $dir . '/' . md5(microtime(true)) . '.png'; |
456
|
|
|
(new LocalFile())->downloadFile([$url, $fileName]); |
457
|
|
|
return $fileName; |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
/** |
461
|
|
|
* 释放输入输出图片 |
462
|
|
|
*/ |
463
|
|
|
public function __destruct() |
464
|
|
|
{ |
465
|
|
|
$this->destroy(); |
466
|
|
|
} |
467
|
|
|
} |
468
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.