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

JBZoo / SimpleTypes / 30191090148

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

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%)

88.45 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);
534✔
53
    }
54

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

59
        return $this->text();
6✔
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');
6✔
74

75
        return ['dump' => $this->dump(false)];
6✔
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');
6✔
86
        $this->prepareObject($data['dump'] ?? '');
6✔
87
        $this->log('<-- Wakeup finish');
6✔
88
    }
89

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

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

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

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

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

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

122
    /**
123
     * @noinspection MagicMethodsValidityInspection
124
     */
125
    public function __set(string $name, mixed $value): void
126
    {
127
        if ($name === 'value') {
12✔
128
            $this->set([$value]);
6✔
129
        } elseif ($name === 'rule') {
12✔
130
            $this->convert($value);
6✔
131
        } else {
132
            throw new Exception("{$this->type}: Undefined __set() called: '{$name}' = '{$value}'");
6✔
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);
24✔
143
        if ($name === 'value') {
24✔
144
            return \call_user_func_array([$this, 'val'], $arguments);
6✔
145
        }
146

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

219
        return $this->formatter->html(
6✔
220
            ['value' => $this->val($rule), 'rule' => $rule],
6✔
221
            ['value' => $this->internalValue, 'rule' => $this->internalRule],
6✔
222
            ['id'    => $this->uniqueId],
6✔
223
        );
6✔
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;
6✔
229
        $this->log("Formatted output in '{$rule}' as 'input'");
6✔
230

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

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

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

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

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

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

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

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

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

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

277
    public function getClone(): self
278
    {
279
        return clone $this;
12✔
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);
42✔
292

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

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

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

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

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

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

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

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

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

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

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

335
    public function add(array|float|int|self|string|null $value, bool $getClone = false): self
336
    {
337
        return $this->customAdd($value, $getClone);
54✔
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);
30✔
343
    }
344

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

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

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

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

360
        return $obj;
144✔
361
    }
362

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

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

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

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

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

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

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

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

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

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

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

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

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

423
        return $result;
6✔
424
    }
425

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

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

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

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

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

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

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

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

456
        return $this;
24✔
457
    }
458

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

475
        return $value;
126✔
476
    }
477

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

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

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

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

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

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

509
        return $this;
12✔
510
    }
511

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

520
        return $this;
12✔
521
    }
522

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

530
        return $this;
12✔
531
    }
532

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

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

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

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

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

551
        return $config;
534✔
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);
198✔
560
        $target = $this->parser->checkRule($rule);
198✔
561

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

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

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

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

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

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

600
        return $result;
198✔
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);
66✔
609

610
        $addValue = 0;
60✔
611

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

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

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

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

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

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

642
            return $clone;
12✔
643
        }
644

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

648
        return $this;
102✔
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';
534✔
655

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

662
            // set default rule
663
            $this->default = \strtolower(\trim($config->default));
534✔
664
            if (isStrEmpty($this->default)) {
534✔
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);
534✔
670
        } else {
UNCOV
671
            $this->formatter = new Formatter();
×
672
        }
673

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

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

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

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

690
        // success log
691
        $this->log("Id={$this->uniqueId} has just created; dump='{$this->dump(false)}'");
528✔
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