FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
luhn-algorithm/Src/Luhn.php at main · TheWebSolver/luhn-algorithm · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
TheWebSolver
/
luhn-algorithm
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
0
Pull requests
0
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
luhn-algorithm
/
Src
/
Luhn.php
Copy path
More file actions
More file actions
Latest commit
History
History
History
118 lines (92 loc) · 3.77 KB
Breadcrumbs
luhn-algorithm
/
Src
/
Luhn.php
Copy path
File metadata and controls
118 lines (92 loc) · 3.77 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?php
declare
( strict_types =
1
);
namespace
TheWebSolver
\
Codegarage
\
Validator
;
use
LogicException
;
trait
Luhn {
private
const
ALLOWED_PATTERN
=
'
/[^0-9]/
'
;
private
const
EMPTY_VALUE
=
'
REPRESENTS EMPTY CHECKSUM VALUE @Luhn
'
;
private
bool
$
needsDoubling
=
false
;
private
string
$
digits
=
'
0
'
;
private
int
$
checksum
;
private
mixed
$
raw
;
/** @var array<int,array{doubled:bool,result:int}> */
private
array
$
state
;
public
function
__construct
(
mixed
$
value
=
null
) {
if
(
$
value
) {
$
this
->
runAlgorithm
(
$
value
);
}
}
/** @throws LogicException When initialized without value. */
public
function
__toString
():
string
{
return
(
$
this
->
isValid
() ?
''
:
'
in
'
) .
"
valid [#
{
$
this
->
digits
}
] checksum:
{
$
this
->
checksum
}"
;
}
/** @throws LogicException When initialized without value or constructor value & invoked value mismatch. */
public
function
__invoke
(
mixed
$
data
=
null
):
bool
{
return
$
this
->
ensureNumber
(
$
data
??
self
::
EMPTY_VALUE
)->
isValid
();
}
/**
* @return array{isValid:bool,digits:int,checksum:int,state:array<int,array{doubled:bool,result:int}>}
* @throws LogicException When initialized without value.
*/
public
function
__debugInfo
():
array
{
return
[
'
isValid
'
=>
$
this
->
isValid
(),
'
digits
'
=> (
int
)
$
this
->
digits
,
'
checksum
'
=>
$
this
->
checksum
(),
'
state
'
=>
array_reverse
(
$
this
->
state
?? [] ),
];
}
/** @throws LogicException When initialized with empty value. */
public
static
function
validate
(
mixed
$
value
):
bool
{
return
(
new
self
(
$
value
) )();
}
/** @throws LogicException When initialized without value. */
public
function
checksum
():
int
{
return
$
this
->
checksum
??=
$
this
->
ensureNumber
(
$
this
->
raw
??
self
::
EMPTY_VALUE
)->
add
();
}
/** @throws LogicException When initialized without value. */
public
function
isValid
():
bool
{
return
0
===
$
this
->
checksum
() %
10
;
}
public
static
function
normalize
(
string
$
value
):
string
{
return
preg_replace
(
self
::
ALLOWED_PATTERN
, replacement:
''
, subject:
$
value
) ??
''
;
}
private
function
runAlgorithm
(
mixed
$
value
):
static
{
$
this
->
raw
=
$
value
;
return
!
is_scalar
(
$
value
) || ! (
$
v
=
self
::
normalize
( (
string
)
$
value
) ) ||
2
> (
$
l
=
strlen
(
$
v
) )
?
$
this
:
$
this
->
computeDigitsFrom
( value:
$
v
, length:
$
l
-
1
);
}
private
function
computeDigitsFrom
(
string
$
value
,
int
$
length
,
string
$
final
=
''
):
static
{
// Start doubling every second digit from the end of the given value.
for
(
$
i
=
$
length
;
$
i
>=
0
; --
$
i
) {
$
this
->
runAlgorithmFor
(
$
value
, step:
$
i
, carry:
$
final
);
}
$
this
->
digits
=
strrev
(
$
final
);
return
$
this
;
}
private
function
runAlgorithmFor
(
string
$
value
,
int
$
step
,
string
&
$
carry
):
void
{
$
current
=
$
value
[
$
step
];
$
doubled
=
$
this
->
needsDoubling
;
$
carry
.=
$
result
=
$
this
->
maybeDoubleAndAddDigits
( value: (
int
)
$
current
);
$
this
->
state
[
$
step
] =
compact
(
'
doubled
'
,
'
result
'
);
}
private
function
add
():
int
{
return
(
int
)
array_sum
( array:
str_split
(
$
this
->
digits
) );
}
private
function
maybeDoubleAndAddDigits
(
int
$
value
):
int
{
$
double
=
$
this
->
needsDoubling
;
$
this
->
needsDoubling
= !
$
double
;
return
!
$
double
?
$
value
: ( (
$
doubled
=
$
value
*
2
) >
9
? (
$
doubled
%
10
) +
1
:
$
doubled
);
}
private
function
ensureNumber
(
mixed
$
value
):
static
{
if
( !
isset
(
$
this
->
raw
) ) {
return
self
::
EMPTY_VALUE
!==
$
value
?
$
this
->
runAlgorithm
(
$
value
) :
$
this
->
throw
( hasValue:
false
);
}
return
(
self
::
EMPTY_VALUE
===
$
value
||
$
this
->
raw
===
$
value
) ?
$
this
:
$
this
->
throw
( hasValue:
true
);
}
private
function
throw
(
bool
$
hasValue
): never {
$
valueError
=
$
hasValue
?
'
Initialized value does not match with invoked value
'
:
'
Value not provided
'
;
throw
new
LogicException
(
$
valueError
.
'
for Luhn validation.
'
);
}
}
Back
|
FazBrowse Home
|
New Git URL