• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / SimpleTypes / 29896425390

20 Jul 2026 09:00PM UTC coverage: 99.599%. Remained the same
29896425390

push

github

web-flow
Merge pull request #17 from JBZoo/release/8.0

8.0.0 — PHP 8.3+ floor & lock-step major

3 of 3 new or added lines in 1 file covered. (100.0%)

2 existing lines in 1 file now uncovered.

745 of 748 relevant lines covered (99.6%)

58.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.22
/src/Type/AbstractType.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - SimpleTypes.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/SimpleTypes
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\SimpleTypes\Type;
18

19
use JBZoo\SimpleTypes\Config\AbstractConfig;
20
use JBZoo\SimpleTypes\Exception;
21
use JBZoo\SimpleTypes\Formatter;
22
use JBZoo\SimpleTypes\Parser;
23
use JBZoo\Utils\Str;
24

25
use function JBZoo\Utils\isStrEmpty;
26

27
/**
28
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
29
 * @SuppressWarnings(PHPMD.TooManyMethods)
30
 * @SuppressWarnings(PHPMD.ExcessivePublicCount)
31
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
32
 *
33
 * @property string $value
34
 * @property string $rule
35
 */
36
abstract class AbstractType
37
{
38
    protected static int $counter = 0;
39

40
    protected int       $uniqueId      = 0;
41
    protected string    $type          = '';
42
    protected float|int $internalValue = 0;
43
    protected string    $internalRule  = '';
44
    protected string    $default       = '';
45
    protected array     $logs          = [];
46
    protected bool      $isDebug       = false;
47
    protected Parser    $parser;
48
    protected Formatter $formatter;
49

50
    public function __construct(array|float|int|string|null $value = null, ?AbstractConfig $config = null)
51
    {
52
        $this->prepareObject($value, $config);
356✔
53
    }
54

55
    public function __toString()
56
    {
57
        $this->log('__toString() called');
4✔
58

59
        return $this->text();
4✔
60
    }
61

62
    /**
63
     * Serialize the object state (modern replacement for __sleep()).
64
     *
65
     * The whole object graph (config, formatter, parser, ids) is rebuilt from the scalar dump
66
     * on wake-up via prepareObject() - exactly as the previous __sleep()/__wakeup() pair did -
67
     * so only that dump has to be stored.
68
     *
69
     * @return array<string, string>
70
     */
71
    public function __serialize(): array
72
    {
73
        $this->log('Serialized');
4✔
74

75
        return ['dump' => $this->dump(false)];
4✔
76
    }
77

78
    /**
79
     * Wake up after serialize (modern replacement for __wakeup()).
80
     *
81
     * @param array<string, string> $data
82
     */
83
    public function __unserialize(array $data): void
84
    {
85
        $this->log('--> wakeup start');
4✔
86
        $this->prepareObject($data['dump'] ?? '');
4✔
87
        $this->log('<-- Wakeup finish');
4✔
88
    }
89

90
    /**
91
     * Clone object.
92
     */
93
    public function __clone()
94
    {
95
        self::$counter++;
16✔
96
        $recentId       = $this->uniqueId;
16✔
97
        $this->uniqueId = self::$counter;
16✔
98

99
        $this->log(
16✔
100
            "Cloned from id='{$recentId}' and created new with id='{$this->uniqueId}'; dump=" . $this->dump(false),
16✔
101
        );
16✔
102
    }
103

104
    /**
105
     * @return float|string
106
     */
107
    public function __get(string $name)
108
    {
109
        $name = \strtolower($name);
8✔
110

111
        if ($name === 'value') {
8✔
112
            return $this->val();
4✔
113
        }
114

115
        if ($name === 'rule') {
8✔
116
            return $this->getRule();
4✔
117
        }
118

119
        throw new Exception("{$this->type}: Undefined __get() called: '{$name}'");
4✔
120
    }
121

122
    /**
123
     * @noinspection MagicMethodsValidityInspection
124
     */
125
    public function __set(string $name, mixed $value): void
126
    {
127
        if ($name === 'value') {
8✔
128
            $this->set([$value]);
4✔
129
        } elseif ($name === 'rule') {
8✔
130
            $this->convert($value);
4✔
131
        } else {
132
            throw new Exception("{$this->type}: Undefined __set() called: '{$name}' = '{$value}'");
4✔
133
        }
134
    }
135

136
    /**
137
     * Experimental! Methods aliases.
138
     * @deprecated
139
     */
140
    public function __call(string $name, array $arguments): mixed
141
    {
142
        $name = \strtolower($name);
16✔
143
        if ($name === 'value') {
16✔
144
            return \call_user_func_array([$this, 'val'], $arguments);
4✔
145
        }
146

147
        if ($name === 'plus') {
12✔
148
            return \call_user_func_array([$this, 'add'], $arguments);
4✔
149
        }
150

151
        if ($name === 'minus') {
8✔
152
            return \call_user_func_array([$this, 'subtract'], $arguments);
4✔
153
        }
154

155
        throw new Exception("{$this->type}: Called undefined method: '{$name}'");
4✔
156
    }
157

158
    public function __invoke(): self
159
    {
160
        $args         = \func_get_args();
12✔
161
        $argsCount    = \count($args);
12✔
162
        $shortArgList = 1;
12✔
163
        $fullArgList  = 2;
12✔
164

165
        if ($argsCount === 0) {
12✔
166
            $this->error('Undefined arguments');
4✔
167
        } elseif ($argsCount === $shortArgList) {
8✔
168
            $rules = $this->formatter->getList();
4✔
169

170
            if (\array_key_exists($args[0], $rules)) {
4✔
171
                return $this->convert($args[0]);
4✔
172
            }
173

174
            return $this->set($args[0]);
4✔
175
        } elseif ($argsCount === $fullArgList) {
8✔
176
            return $this->set([$args[0], $args[1]]);
4✔
177
        }
178

179
        throw new Exception("{$this->type}: Too many arguments");
4✔
180
    }
181

182
    public function getId(): int
183
    {
184
        return $this->uniqueId;
8✔
185
    }
186

187
    public function val(?string $rule = null): float
188
    {
189
        $rule = Parser::cleanRule($rule);
132✔
190

191
        if ($rule !== $this->internalRule && !isStrEmpty($rule)) {
132✔
192
            return $this->customConvert($rule);
64✔
193
        }
194

195
        return $this->internalValue;
112✔
196
    }
197

198
    public function text(?string $rule = null): string
199
    {
200
        $rule = !isStrEmpty($rule) ? $this->parser->checkRule($rule) : $this->internalRule;
24✔
201
        $this->log("Formatted output in '{$rule}' as 'text'");
24✔
202

203
        return $this->formatter->text($this->val($rule), $rule);
24✔
204
    }
205

206
    public function noStyle(?string $rule = null): string
207
    {
208
        $rule = !isStrEmpty($rule) ? $this->parser->checkRule($rule) : $this->internalRule;
4✔
209
        $this->log("Formatted output in '{$rule}' as 'noStyle'");
4✔
210

211
        return $this->formatter->text($this->val($rule), $rule, false);
4✔
212
    }
213

214
    public function html(?string $rule = null): string
215
    {
216
        $rule = !isStrEmpty($rule) ? $this->parser->checkRule($rule) : $this->internalRule;
4✔
217
        $this->log("Formatted output in '{$rule}' as 'html'");
4✔
218

219
        return $this->formatter->html(
4✔
220
            ['value' => $this->val($rule), 'rule' => $rule],
4✔
221
            ['value' => $this->internalValue, 'rule' => $this->internalRule],
4✔
222
            ['id'    => $this->uniqueId],
4✔
223
        );
4✔
224
    }
225

226
    public function htmlInput(?string $rule = null, ?string $name = null, bool $formatted = false): string
227
    {
228
        $rule = !isStrEmpty($rule) ? $this->parser->checkRule($rule) : $this->internalRule;
4✔
229
        $this->log("Formatted output in '{$rule}' as 'input'");
4✔
230

231
        return $this->formatter->htmlInput(
4✔
232
            ['value' => $this->val($rule), 'rule' => $rule],
4✔
233
            ['value' => $this->internalValue, 'rule' => $this->internalRule],
4✔
234
            ['id'    => $this->uniqueId, 'name' => $name, 'formatted' => $formatted],
4✔
235
        );
4✔
236
    }
237

238
    public function isRule(string $rule): bool
239
    {
240
        $rule = $this->parser->checkRule($rule);
16✔
241

242
        return $rule === $this->internalRule;
16✔
243
    }
244

245
    public function getRule(): string
246
    {
247
        return $this->internalRule;
60✔
248
    }
249

250
    public function isEmpty(): bool
251
    {
252
        return (float)$this->internalValue === 0.0;
8✔
253
    }
254

255
    public function isPositive(): bool
256
    {
257
        return $this->internalValue > 0;
4✔
258
    }
259

260
    public function isNegative(): bool
261
    {
262
        return $this->internalValue < 0;
4✔
263
    }
264

265
    public function getRules(): array
266
    {
267
        return $this->formatter->getList();
4✔
268
    }
269

270
    public function data(bool $toString = false): array|string
271
    {
272
        $data = [(string)$this->val(), $this->getRule()];
4✔
273

274
        return $toString ? \implode(' ', $data) : $data;
4✔
275
    }
276

277
    public function getClone(): self
278
    {
279
        return clone $this;
8✔
280
    }
281

282
    /**
283
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
284
     */
285
    public function compare(
286
        array|float|int|self|string|null $value,
287
        string $mode = '==',
288
        int $round = Formatter::ROUND_DEFAULT,
289
    ): bool {
290
        // prepare value
291
        $value = $this->getValidValue($value);
28✔
292

293
        $mode = \trim($mode);
28✔
294
        $mode = \in_array($mode, ['=', '==', '==='], true) ? '==' : $mode;
28✔
295

296
        $val1 = \round($this->val($this->internalRule), $round);
28✔
297
        $val2 = \round($value->val($this->internalRule), $round);
28✔
298

299
        $this->log(
28✔
300
            "Compared '{$this->dump(false)}' {$mode} '{$value->dump(false)}' // {$val1} {$mode} {$val2}, r={$round}",
28✔
301
        );
28✔
302

303
        if ($mode === '==') {
28✔
304
            return $val1 === $val2;
24✔
305
        }
306

307
        if ($mode === '!=' || $mode === '!==') {
16✔
308
            return $val1 !== $val2;
8✔
309
        }
310

311
        if ($mode === '<') {
16✔
312
            return $val1 < $val2;
12✔
313
        }
314

315
        if ($mode === '>') {
16✔
316
            return $val1 > $val2;
12✔
317
        }
318

319
        if ($mode === '<=') {
16✔
320
            return $val1 <= $val2;
12✔
321
        }
322

323
        if ($mode === '>=') {
16✔
324
            return $val1 >= $val2;
12✔
325
        }
326

327
        throw new Exception("{$this->type}: Undefined compare mode: {$mode}");
4✔
328
    }
329

330
    public function setEmpty(bool $getClone = false): self
331
    {
332
        return $this->modifier(0.0, 'Set empty', $getClone);
4✔
333
    }
334

335
    public function add(array|float|int|self|string|null $value, bool $getClone = false): self
336
    {
337
        return $this->customAdd($value, $getClone);
36✔
338
    }
339

340
    public function subtract(array|float|int|self|string|null $value, bool $getClone = false): self
341
    {
342
        return $this->customAdd($value, $getClone, true);
20✔
343
    }
344

345
    public function convert(string $newRule, bool $getClone = false): self
346
    {
347
        if ($newRule === '') {
104✔
348
            $newRule = $this->internalRule;
4✔
349
        }
350

351
        $newRule = $this->parser->checkRule($newRule);
104✔
352

353
        $obj = $getClone ? clone $this : $this;
96✔
354

355
        if ($newRule !== $obj->internalRule) {
96✔
356
            $obj->internalValue = $obj->customConvert($newRule, true);
92✔
357
            $obj->internalRule  = $newRule;
92✔
358
        }
359

360
        return $obj;
96✔
361
    }
362

363
    public function invert(bool $getClone = false): self
364
    {
365
        $logMess = 'Invert sign';
4✔
366
        if ($this->internalValue > 0) {
4✔
367
            $newValue = -1 * $this->internalValue;
4✔
368
        } elseif ($this->internalValue < 0) {
4✔
369
            $newValue = \abs((float)$this->internalValue);
4✔
370
        } else {
371
            $newValue = $this->internalValue;
4✔
372
        }
373

374
        return $this->modifier($newValue, $logMess, $getClone);
4✔
375
    }
376

377
    public function positive(bool $getClone = false): self
378
    {
379
        return $this->modifier(\abs((float)$this->internalValue), 'Set positive/abs', $getClone);
8✔
380
    }
381

382
    public function negative(bool $getClone = false): self
383
    {
384
        return $this->modifier(-1 * \abs((float)$this->internalValue), 'Set negative', $getClone);
8✔
385
    }
386

387
    public function abs(bool $getClone = false): self
388
    {
389
        return $this->positive($getClone);
4✔
390
    }
391

392
    public function multiply(float $number, bool $getClone = false): self
393
    {
394
        $multiplier = Parser::cleanValue($number);
12✔
395
        $newValue   = $multiplier * $this->internalValue;
12✔
396

397
        return $this->modifier($newValue, "Multiply with '{$multiplier}'", $getClone);
12✔
398
    }
399

400
    public function division(float $number, bool $getClone = false): self
401
    {
402
        $divider = Parser::cleanValue($number);
4✔
403

404
        return $this->modifier($this->internalValue / $divider, "Division with '{$divider}'", $getClone);
4✔
405
    }
406

407
    public function percent(self|string $value, bool $revert = false): self
408
    {
409
        $value = $this->getValidValue($value);
4✔
410

411
        $percent = 0.0;
4✔
412
        if (!$this->isEmpty() && !$value->isEmpty()) {
4✔
413
            $percent = ($this->internalValue / $value->val($this->internalRule)) * 100;
4✔
414
        }
415

416
        if ($revert) {
4✔
417
            $percent = 100 - $percent;
4✔
418
        }
419

420
        $result = $this->getValidValue("{$percent}%");
4✔
421
        $this->log("Calculate percent; '{$this->dump(false)}' / {$value->dump(false)} = {$result->dump(false)}");
4✔
422

423
        return $result;
4✔
424
    }
425

426
    public function customFunc(\Closure $function, bool $getClone = false): self
427
    {
428
        $this->log('--> Function start');
4✔
429
        $function($this);
4✔
430

431
        return $this->modifier($this->internalValue, '<-- Function finished', $getClone);
4✔
432
    }
433

434
    public function set(array|float|int|self|string|null $value, bool $getClone = false): self
435
    {
436
        $value = $this->getValidValue($value);
12✔
437

438
        $this->internalValue = $value->val();
12✔
439
        $this->internalRule  = $value->getRule();
12✔
440

441
        return $this->modifier($this->internalValue, "Set new value = '{$this->dump(false)}'", $getClone);
12✔
442
    }
443

444
    public function round(int $roundValue, string $mode = Formatter::ROUND_CLASSIC): self
445
    {
446
        $oldValue = $this->internalValue;
20✔
447
        $newValue = $this->formatter->round($this->internalValue, $this->internalRule, [
20✔
448
            'roundValue' => $roundValue,
20✔
449
            'roundType'  => $mode,
20✔
450
        ]);
20✔
451

452
        $this->log("Rounded (size={$roundValue}; type={$mode}) '{$oldValue}' => {$newValue}");
16✔
453

454
        $this->internalValue = $newValue;
16✔
455

456
        return $this;
16✔
457
    }
458

459
    public function getValidValue(array|float|int|self|string|null $value): self
460
    {
461
        if ($value instanceof self) {
88✔
462
            $thisClass = \strtolower(static::class);
28✔
463
            $valClass  = \strtolower($value::class);
28✔
464
            if ($thisClass !== $valClass) {
28✔
465
                throw new Exception("{$this->type}: No valid object type given: {$valClass}");
4✔
466
            }
467
        } else {
468
            /**
469
             * @psalm-suppress UnsafeInstantiation
470
             * @phpstan-ignore-next-line
471
             */
472
            $value = new static($value, $this->getConfig());
68✔
473
        }
474

475
        return $value;
84✔
476
    }
477

478
    public function error(string $message): void
479
    {
480
        $this->log($message);
8✔
481
        throw new Exception("{$this->type}: {$message}");
8✔
482
    }
483

484
    public function dump(bool $showId = true): string
485
    {
486
        $uniqueId = $showId ? "; id={$this->uniqueId}" : '';
352✔
487

488
        return "{$this->internalValue} {$this->internalRule}{$uniqueId}";
352✔
489
    }
490

491
    public function log(string $message): void
492
    {
493
        if ($this->isDebug) {
352✔
494
            $this->logs[] = $message;
8✔
495
        }
496
    }
497

498
    public function logs(): array
499
    {
500
        return $this->logs;
4✔
501
    }
502

503
    public function changeRule(string $rule, array $newFormat): self
504
    {
505
        $rule = Parser::cleanRule($rule);
12✔
506
        $this->formatter->changeRule($rule, $newFormat);
12✔
507
        $this->log("The rule '{$rule}' changed");
8✔
508

509
        return $this;
8✔
510
    }
511

512
    public function addRule(string $rule, array $newFormat = []): self
513
    {
514
        $form = $this->formatter;
16✔
515
        $rule = Parser::cleanRule($rule);
16✔
516
        $form->addRule($rule, $newFormat);
16✔
517
        $this->parser->addRule($rule);
8✔
518
        $this->log("The rule '{$rule}' added");
8✔
519

520
        return $this;
8✔
521
    }
522

523
    public function removeRule(string $rule): self
524
    {
525
        $rule = Parser::cleanRule($rule);
8✔
526
        $this->formatter->removeRule($rule);
8✔
527
        $this->parser->removeRule($rule);
8✔
528
        $this->log("The rule '{$rule}' removed");
8✔
529

530
        return $this;
8✔
531
    }
532

533
    public function getRuleData(string $rule): array
534
    {
535
        $rule = Parser::cleanRule($rule);
8✔
536

537
        return $this->formatter->get($rule);
8✔
538
    }
539

540
    protected function getConfig(?AbstractConfig $config = null): ?AbstractConfig
541
    {
542
        $defaultConfig = AbstractConfig::getDefault($this->type);
356✔
543

544
        $config ??= $defaultConfig;
356✔
545

546
        // Hack for getValidValue method
547
        if ($defaultConfig === null && $config !== null) {
356✔
548
            AbstractConfig::registerDefault($this->type, $config);
8✔
549
        }
550

551
        return $config;
356✔
552
    }
553

554
    /**
555
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
556
     */
557
    protected function customConvert(string $rule, bool $addToLog = false): float
558
    {
559
        $from   = $this->parser->checkRule($this->internalRule);
132✔
560
        $target = $this->parser->checkRule($rule);
132✔
561

562
        $ruleTo   = $this->formatter->get($target);
132✔
563
        $ruleFrom = $this->formatter->get($from);
132✔
564
        $ruleDef  = $this->formatter->get($this->default);
132✔
565

566
        $log = "'{$from}'=>'{$target}'";
132✔
567

568
        $result = $this->internalValue;
132✔
569
        if ($from !== $target) {
132✔
570
            if (\is_callable($ruleTo['rate']) || \is_callable($ruleFrom['rate'])) {
132✔
571
                if (\is_callable($ruleFrom['rate'])) {
36✔
572
                    $defNorm = $ruleFrom['rate']($this->internalValue, $this->default, $from);
36✔
573
                } else {
574
                    $defNorm = $this->internalValue * $ruleFrom['rate'] * $ruleDef['rate'];
20✔
575
                }
576

577
                if (\is_callable($ruleTo['rate'])) {
36✔
578
                    $result = $ruleTo['rate']($defNorm, $target, $this->default);
28✔
579
                } else {
580
                    $result = $defNorm / $ruleTo['rate'];
28✔
581
                }
582
            } else {
583
                $defNorm = $this->internalValue * $ruleFrom['rate'] * $ruleDef['rate'];
108✔
584
                $result  = $defNorm / $ruleTo['rate'];
108✔
585
            }
586

587
            if ($this->isDebug && $addToLog) {
132✔
588
                $message = [
4✔
589
                    "Converted {$log};",
4✔
590
                    "New value = {$result} {$target};",
4✔
591
                    \is_callable($ruleTo['rate']) ? "func({$from})" : "{$ruleTo['rate']} {$from}",
4✔
592
                    '=',
4✔
593
                    \is_callable($ruleFrom['rate']) ? "func({$target})" : "{$ruleFrom['rate']} {$target}",
4✔
594
                ];
4✔
595

596
                $this->log(\implode(' ', $message));
4✔
597
            }
598
        }
599

600
        return $result;
132✔
601
    }
602

603
    protected function customAdd(
604
        array|float|int|self|string|null $value,
605
        bool $getClone = false,
606
        bool $isSubtract = false,
607
    ): self {
608
        $value = $this->getValidValue($value);
44✔
609

610
        $addValue = 0;
40✔
611

612
        if ($this->internalRule === '%') {
40✔
613
            if ($value->getRule() === '%') {
8✔
614
                $addValue = $value->val();
4✔
615
            } else {
616
                $this->error("Impossible add '{$value->dump(false)}' to '{$this->dump(false)}'");
4✔
617
            }
618
        } elseif ($value->getRule() !== '%') {
36✔
619
            $addValue = $value->val($this->internalRule);
32✔
620
        } else {
621
            $addValue = $this->internalValue * $value->val() / 100;
12✔
622
        }
623

624
        if ($isSubtract) {
36✔
625
            $addValue *= -1;
20✔
626
        }
627

628
        $newValue = $this->internalValue + $addValue;
36✔
629
        $logMess  = ($isSubtract ? 'Subtract' : 'Add') . " '{$value->dump(false)}'";
36✔
630

631
        return $this->modifier($newValue, $logMess, $getClone);
36✔
632
    }
633

634
    protected function modifier(float $newValue, ?string $logMessage = null, bool $getClone = false): self
635
    {
636
        if ($getClone) {
68✔
637
            $clone = $this->getClone();
8✔
638

639
            $clone->internalValue = $newValue;
8✔
640
            $clone->log("{$logMessage}; New value = '{$clone->dump(false)}'");
8✔
641

642
            return $clone;
8✔
643
        }
644

645
        $this->internalValue = $newValue;
68✔
646
        $this->log("{$logMessage}; New value = '{$this->dump(false)}'");
68✔
647

648
        return $this;
68✔
649
    }
650

651
    private function prepareObject(array|float|int|string|null $value = null, ?AbstractConfig $config = null): void
652
    {
653
        // $this->type = Str::class \strtolower(\str_replace(__NAMESPACE__ . '\\', '', static::class));
654
        $this->type = Str::getClassName(static::class, true) ?? 'UndefinedType';
356✔
655

656
        // get custom or global config
657
        $config = $this->getConfig($config);
356✔
658
        if ($config !== null) {
356✔
659
            // debug flag (for logging)
660
            $this->isDebug = $config->isDebug;
356✔
661

662
            // set default rule
663
            $this->default = \strtolower(\trim($config->default));
356✔
664
            if (isStrEmpty($this->default)) {
356✔
UNCOV
665
                $this->error('Default rule cannot be empty!');
×
666
            }
667

668
            // create formatter helper
669
            $this->formatter = new Formatter($config->getRules(), $config->defaultParams, $this->type);
356✔
670
        } else {
UNCOV
671
            $this->formatter = new Formatter();
×
672
        }
673

674
        // check that default rule
675
        $rules = $this->formatter->getList(true);
356✔
676
        if (!\array_key_exists($this->default, $rules)) {
356✔
677
            throw new Exception("{$this->type}: Default rule not found!");
4✔
678
        }
679

680
        // create parser helper
681
        $this->parser = new Parser($this->default, $rules);
352✔
682

683
        // parse data
684
        [$this->internalValue, $this->internalRule] = $this->parser->parse($value);
352✔
685

686
        // count unique id
687
        self::$counter++;
352✔
688
        $this->uniqueId = self::$counter;
352✔
689

690
        // success log
691
        $this->log("Id={$this->uniqueId} has just created; dump='{$this->dump(false)}'");
352✔
692
    }
693
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc