| Conditions | 27 |
| Paths | 212 |
| Total Lines | 162 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php // phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase |
||
| 132 | public function parse( $changelog ) { |
||
| 133 | $ret = new Changelog(); |
||
| 134 | |||
| 135 | $bullet = $this->bullet . ' '; |
||
| 136 | $len = strlen( $bullet ); |
||
| 137 | $indent = str_repeat( ' ', $len ); |
||
| 138 | |||
| 139 | // Fix newlines and expand tabs. |
||
| 140 | $changelog = strtr( $changelog, array( "\r\n" => "\n" ) ); |
||
| 141 | $changelog = strtr( $changelog, array( "\r" => "\n" ) ); |
||
| 142 | while ( strpos( $changelog, "\t" ) !== false ) { |
||
| 143 | $changelog = preg_replace_callback( |
||
| 144 | '/^([^\t\n]*)\t/m', |
||
| 145 | function ( $m ) { |
||
| 146 | return $m[1] . str_repeat( ' ', 4 - ( mb_strlen( $m[1] ) % 4 ) ); |
||
| 147 | }, |
||
| 148 | $changelog |
||
| 149 | ); |
||
| 150 | } |
||
| 151 | |||
| 152 | // Extract link definitions. |
||
| 153 | $links = array(); |
||
| 154 | $usedlinks = array(); |
||
| 155 | while ( ( $m = $this->endsInLink( $changelog ) ) ) { // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition |
||
| 156 | $links[ $m['id'] ] = $m['link']; |
||
| 157 | $usedlinks[ $m['id'] ] = false; |
||
| 158 | $changelog = (string) substr( $changelog, 0, -strlen( $m['match'] ) ); |
||
| 159 | } |
||
| 160 | $links = array_reverse( $links ); |
||
| 161 | |||
| 162 | // Everything up to the first level-2 ATX heading is the prologue. |
||
| 163 | list( $prologue, $changelog ) = $this->split( "\n$changelog", "\n## " ); |
||
| 164 | $ret->setPrologue( $prologue ); |
||
| 165 | |||
| 166 | // Entries make up the rest of the document. |
||
| 167 | $entries = array(); |
||
| 168 | while ( '' !== $changelog ) { |
||
| 169 | // Extract the first entry from the changelog file, then extract the heading from it. |
||
| 170 | list( $content, $changelog ) = $this->split( $changelog, "\n## " ); |
||
| 171 | list( $heading, $content ) = $this->split( $content, "\n" ); |
||
| 172 | |||
| 173 | // Parse the heading and create a ChangelogEntry for it. |
||
| 174 | if ( ! preg_match( '/^## +(\[?[^] ]+\]?) - (.+?) *$/', $heading, $m ) ) { |
||
| 175 | throw new InvalidArgumentException( "Invalid heading: $heading" ); |
||
| 176 | } |
||
| 177 | $link = null; |
||
| 178 | $version = $m[1]; |
||
| 179 | $timestamp = $m[2]; |
||
| 180 | if ( '[' === $version[0] && ']' === substr( $version, -1 ) ) { |
||
| 181 | $version = substr( $version, 1, -1 ); |
||
| 182 | if ( ! isset( $links[ $version ] ) ) { |
||
| 183 | throw new InvalidArgumentException( "Heading seems to have a linked version, but link was not found: $heading" ); |
||
| 184 | } |
||
| 185 | $link = $links[ $version ]; |
||
| 186 | $usedlinks[ $version ] = true; |
||
| 187 | } |
||
| 188 | if ( $timestamp === $this->unreleased ) { |
||
| 189 | $timestamp = null; |
||
| 190 | $entryTimestamp = new DateTime( 'now', new DateTimeZone( 'UTC' ) ); |
||
| 191 | } else { |
||
| 192 | try { |
||
| 193 | $timestamp = new DateTime( $timestamp, new DateTimeZone( 'UTC' ) ); |
||
| 194 | } catch ( \Exception $ex ) { |
||
| 195 | throw new InvalidArgumentException( "Heading has an invalid timestamp: $heading", 0, $ex ); |
||
| 196 | } |
||
| 197 | if ( strtotime( $m[2], 0 ) !== strtotime( $m[2], 1000000000 ) ) { |
||
| 198 | throw new InvalidArgumentException( "Heading has a relative timestamp: $heading" ); |
||
| 199 | } |
||
| 200 | $entryTimestamp = $timestamp; |
||
| 201 | } |
||
| 202 | $entry = $this->newChangelogEntry( |
||
| 203 | $version, |
||
| 204 | array( |
||
| 205 | 'link' => $link, |
||
| 206 | 'timestamp' => $timestamp, |
||
| 207 | ) |
||
| 208 | ); |
||
| 209 | $entries[] = $entry; |
||
| 210 | |||
| 211 | // Extract the prologue, if any. |
||
| 212 | list( $prologue, $content ) = $this->split( "\n$content", "\n### ", "\n$bullet" ); |
||
| 213 | $entry->setPrologue( $prologue ); |
||
| 214 | |||
| 215 | if ( '' === $content ) { |
||
| 216 | // Huh, no changes. |
||
| 217 | continue; |
||
| 218 | } |
||
| 219 | |||
| 220 | // Inject an empty heading if necessary so the change parsing can be more straightforward. |
||
| 221 | if ( '#' !== $content[0] ) { |
||
| 222 | $content = "### \n$content"; |
||
| 223 | } |
||
| 224 | |||
| 225 | // Now parse all the subheadings and changes. |
||
| 226 | while ( '' !== $content ) { |
||
| 227 | list( $section, $content ) = $this->split( $content, "\n### " ); |
||
| 228 | list( $subheading, $section ) = $this->split( $section, "\n" ); |
||
| 229 | $subheading = trim( substr( $subheading, 4 ) ); |
||
| 230 | $changes = array(); |
||
| 231 | $cur = ''; |
||
| 232 | $section = explode( "\n", $section ); |
||
| 233 | while ( $section ) { |
||
| 234 | $line = array_shift( $section ); |
||
| 235 | $prefix = substr( $line, 0, $len ); |
||
| 236 | if ( $prefix === $bullet ) { |
||
| 237 | $cur = trim( $cur ); |
||
| 238 | if ( '' !== $cur ) { |
||
| 239 | $changes[] = $cur; |
||
| 240 | } |
||
| 241 | $cur = substr( $line, $len ) . "\n"; |
||
| 242 | } elseif ( $prefix === $indent ) { |
||
| 243 | $cur .= substr( $line, $len ) . "\n"; |
||
| 244 | } elseif ( '' === $line ) { |
||
| 245 | $cur .= "\n"; |
||
| 246 | } else { |
||
| 247 | // If there are no more subsections and the rest of the lines don't contain |
||
| 248 | // bullets, assume it's an epilogue. Otherwise, assume it's an error. |
||
| 249 | $section = $line . "\n" . implode( "\n", $section ); |
||
| 250 | if ( '' === $content && strpos( $section, "\n$bullet" ) === false ) { |
||
| 251 | $entry->setEpilogue( $section ); |
||
| 252 | break; |
||
| 253 | } else { |
||
| 254 | throw new InvalidArgumentException( "Malformatted changes list near \"$line\"" ); |
||
| 255 | } |
||
| 256 | } |
||
| 257 | } |
||
| 258 | $cur = trim( $cur ); |
||
| 259 | if ( '' !== $cur ) { |
||
| 260 | $changes[] = $cur; |
||
| 261 | } |
||
| 262 | foreach ( $changes as $change ) { |
||
| 263 | $author = ''; |
||
| 264 | if ( $this->parseAuthors && preg_match( '/ \(([^()\n]+)\)$/', $change, $m ) ) { |
||
| 265 | $author = $m[1]; |
||
| 266 | $change = substr( $change, 0, -strlen( $m[0] ) ); |
||
| 267 | } |
||
| 268 | $entry->appendChange( |
||
| 269 | $this->newChangeEntry( |
||
| 270 | array( |
||
| 271 | 'subheading' => $subheading, |
||
| 272 | 'author' => $author, |
||
| 273 | 'content' => $change, |
||
| 274 | 'timestamp' => $entryTimestamp, |
||
| 275 | ) |
||
| 276 | ) |
||
| 277 | ); |
||
| 278 | } |
||
| 279 | } |
||
| 280 | } |
||
| 281 | $ret->setEntries( $entries ); |
||
| 282 | |||
| 283 | // Append any unused links to the epilogue. |
||
| 284 | $epilogue = $ret->getEpilogue(); |
||
| 285 | foreach ( $links as $id => $content ) { |
||
| 286 | if ( empty( $usedlinks[ $id ] ) ) { |
||
| 287 | $epilogue .= "\n[$id]: $content"; |
||
| 288 | } |
||
| 289 | } |
||
| 290 | $ret->setEpilogue( $epilogue ); |
||
| 291 | |||
| 292 | return $ret; |
||
| 293 | } |
||
| 294 | |||
| 375 |
This check looks for
@paramannotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.